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;
1332 /* Space for saved registers */
1333 cfg->arch.iregs_offset = offset;
1335 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1337 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1339 if (iregs_to_save) {
1340 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1341 if (iregs_to_save & (1 << i)) {
1342 offset += SIZEOF_REGISTER;
1347 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1348 * args or return vals. Extra stack space avoids this in a lot of cases.
1350 offset += EXTRA_STACK_SPACE;
1352 /* saved float registers */
1354 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1355 if (fregs_to_restore) {
1356 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1357 if (fregs_to_restore & (1 << i)) {
1358 offset += sizeof(double);
1364 #if _MIPS_SIM == _ABIO32
1365 /* Now add space for saving the ra */
1366 offset += SIZEOF_VOID_P;
1369 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1370 cfg->stack_offset = offset;
1371 cfg->arch.local_alloc_offset = cfg->stack_offset;
1375 * Now allocate stack slots for the int arg regs (a0 - a3)
1376 * On MIPS o32, these are just above the incoming stack pointer
1377 * Even if the arg has been assigned to a regvar, it gets a stack slot
1380 /* Return struct-by-value results in a hidden first argument */
1381 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1382 cfg->vret_addr->opcode = OP_REGOFFSET;
1383 cfg->vret_addr->inst_c0 = mips_a0;
1384 cfg->vret_addr->inst_offset = offset;
1385 cfg->vret_addr->inst_basereg = frame_reg;
1386 offset += SIZEOF_REGISTER;
1389 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1390 inst = cfg->args [i];
1391 if (inst->opcode != OP_REGVAR) {
1394 if (sig->hasthis && (i == 0))
1395 arg_type = &mono_defaults.object_class->byval_arg;
1397 arg_type = sig->params [i - sig->hasthis];
1399 inst->opcode = OP_REGOFFSET;
1400 size = mono_type_size (arg_type, &align);
1402 if (size < SIZEOF_REGISTER) {
1403 size = SIZEOF_REGISTER;
1404 align = SIZEOF_REGISTER;
1406 inst->inst_basereg = frame_reg;
1407 offset = (offset + align - 1) & ~(align - 1);
1408 inst->inst_offset = offset;
1410 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1411 cfg->sig_cookie += size;
1412 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1415 #if _MIPS_SIM == _ABIO32
1416 /* o32: Even a0-a3 get stack slots */
1417 size = SIZEOF_REGISTER;
1418 align = SIZEOF_REGISTER;
1419 inst->inst_basereg = frame_reg;
1420 offset = (offset + align - 1) & ~(align - 1);
1421 inst->inst_offset = offset;
1423 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1424 cfg->sig_cookie += size;
1425 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1429 #if _MIPS_SIM == _ABIN32
1430 /* Now add space for saving the ra */
1431 offset += SIZEOF_VOID_P;
1434 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1435 cfg->stack_offset = offset;
1436 cfg->arch.local_alloc_offset = cfg->stack_offset;
1441 mono_arch_create_vars (MonoCompile *cfg)
1443 MonoMethodSignature *sig;
1445 sig = mono_method_signature (cfg->method);
1447 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1448 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1449 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1450 printf ("vret_addr = ");
1451 mono_print_ins (cfg->vret_addr);
1456 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1457 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1461 * take the arguments and generate the arch-specific
1462 * instructions to properly call the function in call.
1463 * This includes pushing, moving arguments to the right register
1465 * Issue: who does the spilling if needed, and when?
1468 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1470 int sig_reg = mono_alloc_ireg (cfg);
1472 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1473 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1474 mips_sp, cinfo->sig_cookie.offset, sig_reg);
1478 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1481 MonoMethodSignature *sig;
1486 sig = call->signature;
1487 n = sig->param_count + sig->hasthis;
1489 cinfo = calculate_sizes (sig, sig->pinvoke);
1490 if (cinfo->struct_ret)
1491 call->used_iregs |= 1 << cinfo->struct_ret;
1493 for (i = 0; i < n; ++i) {
1494 ArgInfo *ainfo = cinfo->args + i;
1497 if (i >= sig->hasthis)
1498 t = sig->params [i - sig->hasthis];
1500 t = &mono_defaults.int_class->byval_arg;
1501 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1503 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1504 emit_sig_cookie (cfg, call, cinfo);
1505 if (is_virtual && i == 0) {
1506 /* the argument will be attached to the call instrucion */
1507 in = call->args [i];
1508 call->used_iregs |= 1 << ainfo->reg;
1511 in = call->args [i];
1512 if (ainfo->regtype == RegTypeGeneral) {
1513 #if SIZEOF_REGISTER == 4
1514 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1515 MONO_INST_NEW (cfg, ins, OP_MOVE);
1516 ins->dreg = mono_alloc_ireg (cfg);
1517 ins->sreg1 = in->dreg + 1;
1518 MONO_ADD_INS (cfg->cbb, ins);
1519 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1521 MONO_INST_NEW (cfg, ins, OP_MOVE);
1522 ins->dreg = mono_alloc_ireg (cfg);
1523 ins->sreg1 = in->dreg + 2;
1524 MONO_ADD_INS (cfg->cbb, ins);
1525 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1528 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1531 #if PROMOTE_R4_TO_R8
1532 /* ??? - convert to single first? */
1533 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1534 ins->dreg = mono_alloc_freg (cfg);
1535 ins->sreg1 = in->dreg;
1536 MONO_ADD_INS (cfg->cbb, ins);
1541 /* trying to load float value into int registers */
1542 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1543 ins->dreg = mono_alloc_ireg (cfg);
1545 MONO_ADD_INS (cfg->cbb, ins);
1546 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1547 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1548 /* trying to load float value into int registers */
1549 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1550 ins->dreg = mono_alloc_ireg (cfg);
1551 ins->sreg1 = in->dreg;
1552 MONO_ADD_INS (cfg->cbb, ins);
1553 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1555 MONO_INST_NEW (cfg, ins, OP_MOVE);
1556 ins->dreg = mono_alloc_ireg (cfg);
1557 ins->sreg1 = in->dreg;
1558 MONO_ADD_INS (cfg->cbb, ins);
1559 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1561 } else if (ainfo->regtype == RegTypeStructByAddr) {
1562 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1563 ins->opcode = OP_OUTARG_VT;
1564 ins->sreg1 = in->dreg;
1565 ins->klass = in->klass;
1566 ins->inst_p0 = call;
1567 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1568 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1569 MONO_ADD_INS (cfg->cbb, ins);
1570 } else if (ainfo->regtype == RegTypeStructByVal) {
1571 /* this is further handled in mono_arch_emit_outarg_vt () */
1572 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1573 ins->opcode = OP_OUTARG_VT;
1574 ins->sreg1 = in->dreg;
1575 ins->klass = in->klass;
1576 ins->inst_p0 = call;
1577 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1578 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1579 MONO_ADD_INS (cfg->cbb, ins);
1580 } else if (ainfo->regtype == RegTypeBase) {
1581 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1582 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1583 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1584 if (t->type == MONO_TYPE_R8)
1585 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1587 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1589 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1591 } else if (ainfo->regtype == RegTypeFP) {
1592 if (t->type == MONO_TYPE_VALUETYPE) {
1593 /* this is further handled in mono_arch_emit_outarg_vt () */
1594 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1595 ins->opcode = OP_OUTARG_VT;
1596 ins->sreg1 = in->dreg;
1597 ins->klass = in->klass;
1598 ins->inst_p0 = call;
1599 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1600 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1601 MONO_ADD_INS (cfg->cbb, ins);
1603 cfg->flags |= MONO_CFG_HAS_FPOUT;
1605 int dreg = mono_alloc_freg (cfg);
1607 if (ainfo->size == 4) {
1608 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1610 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1612 ins->sreg1 = in->dreg;
1613 MONO_ADD_INS (cfg->cbb, ins);
1616 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1617 cfg->flags |= MONO_CFG_HAS_FPOUT;
1620 g_assert_not_reached ();
1624 /* Emit the signature cookie in the case that there is no
1625 additional argument */
1626 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1627 emit_sig_cookie (cfg, call, cinfo);
1629 if (cinfo->struct_ret) {
1632 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1633 vtarg->sreg1 = call->vret_var->dreg;
1634 vtarg->dreg = mono_alloc_preg (cfg);
1635 MONO_ADD_INS (cfg->cbb, vtarg);
1637 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1641 * Reverse the call->out_args list.
1644 MonoInst *prev = NULL, *list = call->out_args, *next;
1651 call->out_args = prev;
1654 call->stack_usage = cinfo->stack_usage;
1655 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1656 #if _MIPS_SIM == _ABIO32
1657 /* a0-a3 always present */
1658 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1660 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1661 cfg->flags |= MONO_CFG_HAS_CALLS;
1663 * should set more info in call, such as the stack space
1664 * used by the args that needs to be added back to esp
1671 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1673 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1674 ArgInfo *ainfo = ins->inst_p1;
1675 int ovf_size = ainfo->vtsize;
1676 int doffset = ainfo->offset;
1677 int i, soffset, dreg;
1679 if (ainfo->regtype == RegTypeStructByVal) {
1681 if (cfg->verbose_level > 0) {
1682 char* nm = mono_method_full_name (cfg->method, TRUE);
1683 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1684 nm, doffset, ainfo->size, ovf_size);
1690 for (i = 0; i < ainfo->size; ++i) {
1691 dreg = mono_alloc_ireg (cfg);
1692 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1693 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1694 soffset += SIZEOF_REGISTER;
1696 if (ovf_size != 0) {
1697 mini_emit_memcpy (cfg, mips_fp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1699 } else if (ainfo->regtype == RegTypeFP) {
1700 int tmpr = mono_alloc_freg (cfg);
1702 if (ainfo->size == 4)
1703 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1705 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1706 dreg = mono_alloc_freg (cfg);
1707 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1708 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1710 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1714 /* FIXME: alignment? */
1715 if (call->signature->pinvoke) {
1716 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1717 vtcopy->backend.is_pinvoke = 1;
1719 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1722 g_assert (ovf_size > 0);
1724 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1725 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1728 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1730 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1735 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1737 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1738 mono_method_signature (method)->ret);
1741 #if (SIZEOF_REGISTER == 4)
1742 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1745 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1746 ins->sreg1 = val->dreg + 1;
1747 ins->sreg2 = val->dreg + 2;
1748 MONO_ADD_INS (cfg->cbb, ins);
1752 if (ret->type == MONO_TYPE_R8) {
1753 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1756 if (ret->type == MONO_TYPE_R4) {
1757 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1761 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1765 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1767 MonoInst *ins, *n, *last_ins = NULL;
1769 if (cfg->verbose_level > 2)
1770 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1773 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1774 if (cfg->verbose_level > 2)
1775 mono_print_ins_index (0, ins);
1777 switch (ins->opcode) {
1779 case OP_LOAD_MEMBASE:
1780 case OP_LOADI4_MEMBASE:
1782 * OP_IADD reg2, reg1, const1
1783 * OP_LOAD_MEMBASE const2(reg2), reg3
1785 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1787 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)){
1788 int const1 = last_ins->inst_imm;
1789 int const2 = ins->inst_offset;
1791 if (mips_is_imm16 (const1 + const2)) {
1792 ins->inst_basereg = last_ins->sreg1;
1793 ins->inst_offset = const1 + const2;
1803 bb->last_ins = last_ins;
1807 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1809 MonoInst *ins, *n, *last_ins = NULL;
1812 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1813 MonoInst *last_ins = ins->prev;
1815 switch (ins->opcode) {
1817 /* remove unnecessary multiplication with 1 */
1818 if (ins->inst_imm == 1) {
1819 if (ins->dreg != ins->sreg1) {
1820 ins->opcode = OP_MOVE;
1822 MONO_DELETE_INS (bb, ins);
1826 int power2 = mono_is_power_of_two (ins->inst_imm);
1828 ins->opcode = OP_SHL_IMM;
1829 ins->inst_imm = power2;
1833 case OP_LOAD_MEMBASE:
1834 case OP_LOADI4_MEMBASE:
1836 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1837 * OP_LOAD_MEMBASE offset(basereg), reg
1839 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1840 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1841 ins->inst_basereg == last_ins->inst_destbasereg &&
1842 ins->inst_offset == last_ins->inst_offset) {
1843 if (ins->dreg == last_ins->sreg1) {
1844 MONO_DELETE_INS (bb, ins);
1847 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1848 ins->opcode = OP_MOVE;
1849 ins->sreg1 = last_ins->sreg1;
1854 * Note: reg1 must be different from the basereg in the second load
1855 * OP_LOAD_MEMBASE offset(basereg), reg1
1856 * OP_LOAD_MEMBASE offset(basereg), reg2
1858 * OP_LOAD_MEMBASE offset(basereg), reg1
1859 * OP_MOVE reg1, reg2
1861 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1862 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1863 ins->inst_basereg != last_ins->dreg &&
1864 ins->inst_basereg == last_ins->inst_basereg &&
1865 ins->inst_offset == last_ins->inst_offset) {
1867 if (ins->dreg == last_ins->dreg) {
1868 MONO_DELETE_INS (bb, ins);
1871 ins->opcode = OP_MOVE;
1872 ins->sreg1 = last_ins->dreg;
1875 //g_assert_not_reached ();
1880 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1881 * OP_LOAD_MEMBASE offset(basereg), reg
1883 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1884 * OP_ICONST reg, imm
1886 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1887 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1888 ins->inst_basereg == last_ins->inst_destbasereg &&
1889 ins->inst_offset == last_ins->inst_offset) {
1890 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1891 ins->opcode = OP_ICONST;
1892 ins->inst_c0 = last_ins->inst_imm;
1893 g_assert_not_reached (); // check this rule
1898 case OP_LOADU1_MEMBASE:
1899 case OP_LOADI1_MEMBASE:
1900 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1901 ins->inst_basereg == last_ins->inst_destbasereg &&
1902 ins->inst_offset == last_ins->inst_offset) {
1903 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1904 ins->sreg1 = last_ins->sreg1;
1907 case OP_LOADU2_MEMBASE:
1908 case OP_LOADI2_MEMBASE:
1909 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1910 ins->inst_basereg == last_ins->inst_destbasereg &&
1911 ins->inst_offset == last_ins->inst_offset) {
1912 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1913 ins->sreg1 = last_ins->sreg1;
1916 case OP_ICONV_TO_I4:
1917 case OP_ICONV_TO_U4:
1919 ins->opcode = OP_MOVE;
1923 if (ins->dreg == ins->sreg1) {
1924 MONO_DELETE_INS (bb, ins);
1928 * OP_MOVE sreg, dreg
1929 * OP_MOVE dreg, sreg
1931 if (last_ins && last_ins->opcode == OP_MOVE &&
1932 ins->sreg1 == last_ins->dreg &&
1933 ins->dreg == last_ins->sreg1) {
1934 MONO_DELETE_INS (bb, ins);
1942 bb->last_ins = last_ins;
1946 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
1954 switch (ins->opcode) {
1957 case OP_LCOMPARE_IMM:
1958 mono_print_ins (ins);
1959 g_assert_not_reached ();
1962 tmp1 = mono_alloc_ireg (cfg);
1963 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1964 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1965 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1966 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1971 tmp1 = mono_alloc_ireg (cfg);
1972 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1973 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1974 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1975 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1980 tmp1 = mono_alloc_ireg (cfg);
1981 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1982 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1983 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1984 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1989 tmp1 = mono_alloc_ireg (cfg);
1990 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1991 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1992 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1993 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2005 mono_print_ins (ins);
2006 g_assert_not_reached ();
2009 tmp1 = mono_alloc_ireg (cfg);
2010 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2011 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2012 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2013 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2021 case OP_LCONV_TO_I1:
2022 case OP_LCONV_TO_I2:
2023 case OP_LCONV_TO_I4:
2024 case OP_LCONV_TO_I8:
2025 case OP_LCONV_TO_R4:
2026 case OP_LCONV_TO_R8:
2027 case OP_LCONV_TO_U4:
2028 case OP_LCONV_TO_U8:
2029 case OP_LCONV_TO_U2:
2030 case OP_LCONV_TO_U1:
2032 case OP_LCONV_TO_OVF_I:
2033 case OP_LCONV_TO_OVF_U:
2035 mono_print_ins (ins);
2036 g_assert_not_reached ();
2039 tmp1 = mono_alloc_ireg (cfg);
2040 tmp2 = mono_alloc_ireg (cfg);
2041 tmp3 = mono_alloc_ireg (cfg);
2042 tmp4 = mono_alloc_ireg (cfg);
2043 tmp5 = mono_alloc_ireg (cfg);
2045 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2047 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2048 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2050 /* add the high 32-bits, and add in the carry from the low 32-bits */
2051 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2052 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2054 /* Overflow happens if
2055 * neg + neg = pos or
2057 * XOR of the high bits returns 0 if the signs match
2058 * XOR of that with the high bit of the result return 1 if overflow.
2061 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2062 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2064 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2065 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2066 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2068 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2069 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2070 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2072 /* Now, if (tmp4 == 0) then overflow */
2073 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2077 case OP_LADD_OVF_UN:
2078 tmp1 = mono_alloc_ireg (cfg);
2079 tmp2 = mono_alloc_ireg (cfg);
2081 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2082 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2083 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2084 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2085 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2086 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2091 case OP_LMUL_OVF_UN:
2092 mono_print_ins (ins);
2093 g_assert_not_reached ();
2096 tmp1 = mono_alloc_ireg (cfg);
2097 tmp2 = mono_alloc_ireg (cfg);
2098 tmp3 = mono_alloc_ireg (cfg);
2099 tmp4 = mono_alloc_ireg (cfg);
2100 tmp5 = mono_alloc_ireg (cfg);
2102 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2104 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2105 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2106 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2108 /* Overflow happens if
2109 * neg - pos = pos or
2111 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2113 * tmp1 = (lhs ^ rhs)
2114 * tmp2 = (lhs ^ result)
2115 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2118 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2119 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2120 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2121 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2123 /* Now, if (tmp4 == 1) then overflow */
2124 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2128 case OP_LSUB_OVF_UN:
2129 tmp1 = mono_alloc_ireg (cfg);
2130 tmp2 = mono_alloc_ireg (cfg);
2132 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2133 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2134 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2135 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2137 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2138 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2142 case OP_LCONV_TO_OVF_I1_UN:
2143 case OP_LCONV_TO_OVF_I2_UN:
2144 case OP_LCONV_TO_OVF_I4_UN:
2145 case OP_LCONV_TO_OVF_I8_UN:
2146 case OP_LCONV_TO_OVF_U1_UN:
2147 case OP_LCONV_TO_OVF_U2_UN:
2148 case OP_LCONV_TO_OVF_U4_UN:
2149 case OP_LCONV_TO_OVF_U8_UN:
2150 case OP_LCONV_TO_OVF_I_UN:
2151 case OP_LCONV_TO_OVF_U_UN:
2152 case OP_LCONV_TO_OVF_I1:
2153 case OP_LCONV_TO_OVF_U1:
2154 case OP_LCONV_TO_OVF_I2:
2155 case OP_LCONV_TO_OVF_U2:
2156 case OP_LCONV_TO_OVF_I4:
2157 case OP_LCONV_TO_OVF_U4:
2158 case OP_LCONV_TO_OVF_I8:
2159 case OP_LCONV_TO_OVF_U8:
2167 case OP_LCONV_TO_R_UN:
2173 case OP_LSHR_UN_IMM:
2175 case OP_LDIV_UN_IMM:
2177 case OP_LREM_UN_IMM:
2188 mono_print_ins (ins);
2189 g_assert_not_reached ();
2191 case OP_LCONV_TO_R8_2:
2192 case OP_LCONV_TO_R4_2:
2193 case OP_LCONV_TO_R_UN_2:
2195 case OP_LCONV_TO_OVF_I4_2:
2196 tmp1 = mono_alloc_ireg (cfg);
2198 /* Overflows if reg2 != sign extension of reg1 */
2199 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2200 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2201 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2209 mono_print_ins (ins);
2210 g_assert_not_reached ();
2218 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2226 switch (ins->opcode) {
2228 tmp1 = mono_alloc_ireg (cfg);
2229 tmp2 = mono_alloc_ireg (cfg);
2230 tmp3 = mono_alloc_ireg (cfg);
2231 tmp4 = mono_alloc_ireg (cfg);
2232 tmp5 = mono_alloc_ireg (cfg);
2234 /* add the operands */
2236 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2238 /* Overflow happens if
2239 * neg + neg = pos or
2242 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2243 * XOR of the high bit returns 0 if the signs match
2244 * XOR of that with the high bit of the result return 1 if overflow.
2247 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2248 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2250 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2251 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2252 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2254 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2255 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2257 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2259 /* Now, if (tmp5 == 0) then overflow */
2260 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2261 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2262 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2266 case OP_IADD_OVF_UN:
2267 tmp1 = mono_alloc_ireg (cfg);
2269 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2270 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2271 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2272 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2273 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2278 tmp1 = mono_alloc_ireg (cfg);
2279 tmp2 = mono_alloc_ireg (cfg);
2280 tmp3 = mono_alloc_ireg (cfg);
2281 tmp4 = mono_alloc_ireg (cfg);
2282 tmp5 = mono_alloc_ireg (cfg);
2284 /* add the operands */
2286 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2288 /* Overflow happens if
2289 * neg - pos = pos or
2291 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2293 * tmp1 = (lhs ^ rhs)
2294 * tmp2 = (lhs ^ result)
2295 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2298 /* tmp3 = 1 if the signs of the two inputs differ */
2299 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2300 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2301 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2302 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2303 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2305 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2306 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2307 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2311 case OP_ISUB_OVF_UN:
2312 tmp1 = mono_alloc_ireg (cfg);
2314 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2315 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2316 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2317 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2318 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2325 map_to_reg_reg_op (int op)
2334 case OP_COMPARE_IMM:
2336 case OP_ICOMPARE_IMM:
2338 case OP_LCOMPARE_IMM:
2354 case OP_LOAD_MEMBASE:
2355 return OP_LOAD_MEMINDEX;
2356 case OP_LOADI4_MEMBASE:
2357 return OP_LOADI4_MEMINDEX;
2358 case OP_LOADU4_MEMBASE:
2359 return OP_LOADU4_MEMINDEX;
2360 case OP_LOADU1_MEMBASE:
2361 return OP_LOADU1_MEMINDEX;
2362 case OP_LOADI2_MEMBASE:
2363 return OP_LOADI2_MEMINDEX;
2364 case OP_LOADU2_MEMBASE:
2365 return OP_LOADU2_MEMINDEX;
2366 case OP_LOADI1_MEMBASE:
2367 return OP_LOADI1_MEMINDEX;
2368 case OP_LOADR4_MEMBASE:
2369 return OP_LOADR4_MEMINDEX;
2370 case OP_LOADR8_MEMBASE:
2371 return OP_LOADR8_MEMINDEX;
2372 case OP_STOREI1_MEMBASE_REG:
2373 return OP_STOREI1_MEMINDEX;
2374 case OP_STOREI2_MEMBASE_REG:
2375 return OP_STOREI2_MEMINDEX;
2376 case OP_STOREI4_MEMBASE_REG:
2377 return OP_STOREI4_MEMINDEX;
2378 case OP_STORE_MEMBASE_REG:
2379 return OP_STORE_MEMINDEX;
2380 case OP_STORER4_MEMBASE_REG:
2381 return OP_STORER4_MEMINDEX;
2382 case OP_STORER8_MEMBASE_REG:
2383 return OP_STORER8_MEMINDEX;
2384 case OP_STORE_MEMBASE_IMM:
2385 return OP_STORE_MEMBASE_REG;
2386 case OP_STOREI1_MEMBASE_IMM:
2387 return OP_STOREI1_MEMBASE_REG;
2388 case OP_STOREI2_MEMBASE_IMM:
2389 return OP_STOREI2_MEMBASE_REG;
2390 case OP_STOREI4_MEMBASE_IMM:
2391 return OP_STOREI4_MEMBASE_REG;
2392 case OP_STOREI8_MEMBASE_IMM:
2393 return OP_STOREI8_MEMBASE_REG;
2395 return mono_op_imm_to_op (op);
2399 map_to_mips_op (int op)
2403 return OP_MIPS_FBEQ;
2405 return OP_MIPS_FBGE;
2407 return OP_MIPS_FBGT;
2409 return OP_MIPS_FBLE;
2411 return OP_MIPS_FBLT;
2413 return OP_MIPS_FBNE;
2415 return OP_MIPS_FBGE_UN;
2417 return OP_MIPS_FBGT_UN;
2419 return OP_MIPS_FBLE_UN;
2421 return OP_MIPS_FBLT_UN;
2429 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2430 g_assert_not_reached ();
2434 #define NEW_INS(cfg,after,dest,op) do { \
2435 MONO_INST_NEW((cfg), (dest), (op)); \
2436 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2439 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2441 MONO_INST_NEW(cfg, temp, (op)); \
2442 mono_bblock_insert_after_ins (bb, (pos), temp); \
2443 temp->dreg = (_dreg); \
2444 temp->sreg1 = (_sreg1); \
2445 temp->sreg2 = (_sreg2); \
2449 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2451 MONO_INST_NEW(cfg, temp, (op)); \
2452 mono_bblock_insert_after_ins (bb, (pos), temp); \
2453 temp->dreg = (_dreg); \
2454 temp->sreg1 = (_sreg1); \
2455 temp->inst_c0 = (_imm); \
2460 * Remove from the instruction list the instructions that can't be
2461 * represented with very simple instructions with no register
2465 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2467 MonoInst *ins, *next, *temp, *last_ins = NULL;
2471 if (cfg->verbose_level > 2) {
2474 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2475 MONO_BB_FOR_EACH_INS (bb, ins) {
2476 mono_print_ins_index (idx++, ins);
2482 MONO_BB_FOR_EACH_INS (bb, ins) {
2484 switch (ins->opcode) {
2489 /* Branch opts can eliminate the branch */
2490 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2496 case OP_COMPARE_IMM:
2497 case OP_ICOMPARE_IMM:
2498 case OP_LCOMPARE_IMM:
2500 /* Branch opts can eliminate the branch */
2501 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2505 if (ins->inst_imm) {
2506 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2507 temp->inst_c0 = ins->inst_imm;
2508 temp->dreg = mono_alloc_ireg (cfg);
2509 ins->sreg2 = temp->dreg;
2513 ins->sreg2 = mips_zero;
2515 if (ins->opcode == OP_COMPARE_IMM)
2516 ins->opcode = OP_COMPARE;
2517 else if (ins->opcode == OP_ICOMPARE_IMM)
2518 ins->opcode = OP_ICOMPARE;
2519 else if (ins->opcode == OP_LCOMPARE_IMM)
2520 ins->opcode = OP_LCOMPARE;
2523 case OP_IDIV_UN_IMM:
2526 case OP_IREM_UN_IMM:
2527 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2528 temp->inst_c0 = ins->inst_imm;
2529 temp->dreg = mono_alloc_ireg (cfg);
2530 ins->sreg2 = temp->dreg;
2531 if (ins->opcode == OP_IDIV_IMM)
2532 ins->opcode = OP_IDIV;
2533 else if (ins->opcode == OP_IREM_IMM)
2534 ins->opcode = OP_IREM;
2535 else if (ins->opcode == OP_IDIV_UN_IMM)
2536 ins->opcode = OP_IDIV_UN;
2537 else if (ins->opcode == OP_IREM_UN_IMM)
2538 ins->opcode = OP_IREM_UN;
2540 /* handle rem separately */
2547 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2548 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2549 temp->inst_c0 = ins->inst_imm;
2550 temp->dreg = mono_alloc_ireg (cfg);
2551 ins->sreg2 = temp->dreg;
2552 ins->opcode = map_to_reg_reg_op (ins->opcode);
2562 /* unsigned 16 bit immediate */
2563 if (ins->inst_imm & 0xffff0000) {
2564 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2565 temp->inst_c0 = ins->inst_imm;
2566 temp->dreg = mono_alloc_ireg (cfg);
2567 ins->sreg2 = temp->dreg;
2568 ins->opcode = map_to_reg_reg_op (ins->opcode);
2575 /* signed 16 bit immediate */
2576 if (!mips_is_imm16 (ins->inst_imm)) {
2577 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2578 temp->inst_c0 = ins->inst_imm;
2579 temp->dreg = mono_alloc_ireg (cfg);
2580 ins->sreg2 = temp->dreg;
2581 ins->opcode = map_to_reg_reg_op (ins->opcode);
2587 if (!mips_is_imm16 (-ins->inst_imm)) {
2588 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2589 temp->inst_c0 = ins->inst_imm;
2590 temp->dreg = mono_alloc_ireg (cfg);
2591 ins->sreg2 = temp->dreg;
2592 ins->opcode = map_to_reg_reg_op (ins->opcode);
2598 if (ins->inst_imm == 1) {
2599 ins->opcode = OP_MOVE;
2602 if (ins->inst_imm == 0) {
2603 ins->opcode = OP_ICONST;
2607 imm = mono_is_power_of_two (ins->inst_imm);
2609 ins->opcode = OP_SHL_IMM;
2610 ins->inst_imm = imm;
2613 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2614 temp->inst_c0 = ins->inst_imm;
2615 temp->dreg = mono_alloc_ireg (cfg);
2616 ins->sreg2 = temp->dreg;
2617 ins->opcode = map_to_reg_reg_op (ins->opcode);
2620 case OP_LOCALLOC_IMM:
2621 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2622 temp->inst_c0 = ins->inst_imm;
2623 temp->dreg = mono_alloc_ireg (cfg);
2624 ins->sreg1 = temp->dreg;
2625 ins->opcode = OP_LOCALLOC;
2628 case OP_LOAD_MEMBASE:
2629 case OP_LOADI4_MEMBASE:
2630 case OP_LOADU4_MEMBASE:
2631 case OP_LOADI2_MEMBASE:
2632 case OP_LOADU2_MEMBASE:
2633 case OP_LOADI1_MEMBASE:
2634 case OP_LOADU1_MEMBASE:
2635 case OP_LOADR4_MEMBASE:
2636 case OP_LOADR8_MEMBASE:
2637 case OP_STORE_MEMBASE_REG:
2638 case OP_STOREI4_MEMBASE_REG:
2639 case OP_STOREI2_MEMBASE_REG:
2640 case OP_STOREI1_MEMBASE_REG:
2641 case OP_STORER4_MEMBASE_REG:
2642 case OP_STORER8_MEMBASE_REG:
2643 /* we can do two things: load the immed in a register
2644 * and use an indexed load, or see if the immed can be
2645 * represented as an ad_imm + a load with a smaller offset
2646 * that fits. We just do the first for now, optimize later.
2648 if (mips_is_imm16 (ins->inst_offset))
2650 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2651 temp->inst_c0 = ins->inst_offset;
2652 temp->dreg = mono_alloc_ireg (cfg);
2653 ins->sreg2 = temp->dreg;
2654 ins->opcode = map_to_reg_reg_op (ins->opcode);
2657 case OP_STORE_MEMBASE_IMM:
2658 case OP_STOREI1_MEMBASE_IMM:
2659 case OP_STOREI2_MEMBASE_IMM:
2660 case OP_STOREI4_MEMBASE_IMM:
2661 case OP_STOREI8_MEMBASE_IMM:
2662 if (!ins->inst_imm) {
2663 ins->sreg1 = mips_zero;
2664 ins->opcode = map_to_reg_reg_op (ins->opcode);
2667 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2668 temp->inst_c0 = ins->inst_imm;
2669 temp->dreg = mono_alloc_ireg (cfg);
2670 ins->sreg1 = temp->dreg;
2671 ins->opcode = map_to_reg_reg_op (ins->opcode);
2673 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2679 /* Branch opts can eliminate the branch */
2680 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2687 * remap compare/branch and compare/set
2688 * to MIPS specific opcodes.
2690 next->opcode = map_to_mips_op (next->opcode);
2691 next->sreg1 = ins->sreg1;
2692 next->sreg2 = ins->sreg2;
2699 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2700 temp->inst_c0 = (guint32)ins->inst_p0;
2701 temp->dreg = mono_alloc_ireg (cfg);
2702 ins->inst_basereg = temp->dreg;
2703 ins->inst_offset = 0;
2704 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2706 /* make it handle the possibly big ins->inst_offset
2707 * later optimize to use lis + load_membase
2712 g_assert (ins_is_compare(last_ins));
2713 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2714 NULLIFY_INS(last_ins);
2718 g_assert (ins_is_compare(last_ins));
2719 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2720 NULLIFY_INS(last_ins);
2724 g_assert (ins_is_compare(last_ins));
2725 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2726 last_ins->dreg = mono_alloc_ireg (cfg);
2727 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2731 g_assert (ins_is_compare(last_ins));
2732 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2733 last_ins->dreg = mono_alloc_ireg (cfg);
2734 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2738 g_assert (ins_is_compare(last_ins));
2739 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2740 last_ins->dreg = mono_alloc_ireg (cfg);
2741 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2745 g_assert (ins_is_compare(last_ins));
2746 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2747 last_ins->dreg = mono_alloc_ireg (cfg);
2748 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2752 g_assert (ins_is_compare(last_ins));
2753 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2754 last_ins->dreg = mono_alloc_ireg (cfg);
2755 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2759 g_assert (ins_is_compare(last_ins));
2760 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2761 last_ins->dreg = mono_alloc_ireg (cfg);
2762 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2766 g_assert (ins_is_compare(last_ins));
2767 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2768 last_ins->dreg = mono_alloc_ireg (cfg);
2769 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2773 g_assert (ins_is_compare(last_ins));
2774 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2775 last_ins->dreg = mono_alloc_ireg (cfg);
2776 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2781 g_assert (ins_is_compare(last_ins));
2782 last_ins->opcode = OP_IXOR;
2783 last_ins->dreg = mono_alloc_ireg(cfg);
2784 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2789 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2790 NULLIFY_INS(last_ins);
2796 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2797 NULLIFY_INS(last_ins);
2802 g_assert (ins_is_compare(last_ins));
2803 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2804 MONO_DELETE_INS(bb, last_ins);
2809 g_assert (ins_is_compare(last_ins));
2810 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2811 MONO_DELETE_INS(bb, last_ins);
2814 case OP_COND_EXC_EQ:
2815 case OP_COND_EXC_IEQ:
2816 g_assert (ins_is_compare(last_ins));
2817 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2818 MONO_DELETE_INS(bb, last_ins);
2821 case OP_COND_EXC_GE:
2822 case OP_COND_EXC_IGE:
2823 g_assert (ins_is_compare(last_ins));
2824 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2825 MONO_DELETE_INS(bb, last_ins);
2828 case OP_COND_EXC_GT:
2829 case OP_COND_EXC_IGT:
2830 g_assert (ins_is_compare(last_ins));
2831 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2832 MONO_DELETE_INS(bb, last_ins);
2835 case OP_COND_EXC_LE:
2836 case OP_COND_EXC_ILE:
2837 g_assert (ins_is_compare(last_ins));
2838 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2839 MONO_DELETE_INS(bb, last_ins);
2842 case OP_COND_EXC_LT:
2843 case OP_COND_EXC_ILT:
2844 g_assert (ins_is_compare(last_ins));
2845 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2846 MONO_DELETE_INS(bb, last_ins);
2849 case OP_COND_EXC_NE_UN:
2850 case OP_COND_EXC_INE_UN:
2851 g_assert (ins_is_compare(last_ins));
2852 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2853 MONO_DELETE_INS(bb, last_ins);
2856 case OP_COND_EXC_GE_UN:
2857 case OP_COND_EXC_IGE_UN:
2858 g_assert (ins_is_compare(last_ins));
2859 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2860 MONO_DELETE_INS(bb, last_ins);
2863 case OP_COND_EXC_GT_UN:
2864 case OP_COND_EXC_IGT_UN:
2865 g_assert (ins_is_compare(last_ins));
2866 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2867 MONO_DELETE_INS(bb, last_ins);
2870 case OP_COND_EXC_LE_UN:
2871 case OP_COND_EXC_ILE_UN:
2872 g_assert (ins_is_compare(last_ins));
2873 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2874 MONO_DELETE_INS(bb, last_ins);
2877 case OP_COND_EXC_LT_UN:
2878 case OP_COND_EXC_ILT_UN:
2879 g_assert (ins_is_compare(last_ins));
2880 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2881 MONO_DELETE_INS(bb, last_ins);
2884 case OP_COND_EXC_OV:
2885 case OP_COND_EXC_IOV: {
2886 int tmp1, tmp2, tmp3, tmp4, tmp5;
2887 MonoInst *pos = last_ins;
2889 /* Overflow happens if
2890 * neg + neg = pos or
2893 * (bit31s of operands match) AND (bit31 of operand
2894 * != bit31 of result)
2895 * XOR of the high bit returns 0 if the signs match
2896 * XOR of that with the high bit of the result return 1
2899 g_assert (last_ins->opcode == OP_IADC);
2901 tmp1 = mono_alloc_ireg (cfg);
2902 tmp2 = mono_alloc_ireg (cfg);
2903 tmp3 = mono_alloc_ireg (cfg);
2904 tmp4 = mono_alloc_ireg (cfg);
2905 tmp5 = mono_alloc_ireg (cfg);
2907 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2908 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2910 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2911 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2912 INS (pos, OP_INOT, tmp3, tmp2, -1);
2914 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2915 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2916 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2918 /* Now, if (tmp5 == 0) then overflow */
2919 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2924 case OP_COND_EXC_NO:
2925 case OP_COND_EXC_INO:
2926 g_assert_not_reached ();
2930 case OP_COND_EXC_IC:
2931 g_assert_not_reached ();
2934 case OP_COND_EXC_NC:
2935 case OP_COND_EXC_INC:
2936 g_assert_not_reached ();
2942 bb->last_ins = last_ins;
2943 bb->max_vreg = cfg->next_vreg;
2946 if (cfg->verbose_level > 2) {
2949 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
2950 MONO_BB_FOR_EACH_INS (bb, ins) {
2951 mono_print_ins_index (idx++, ins);
2960 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2962 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
2964 mips_truncwd (code, mips_ftemp, sreg);
2966 mips_cvtwd (code, mips_ftemp, sreg);
2968 mips_mfc1 (code, dreg, mips_ftemp);
2971 mips_andi (code, dreg, dreg, 0xff);
2972 else if (size == 2) {
2973 mips_sll (code, dreg, dreg, 16);
2974 mips_srl (code, dreg, dreg, 16);
2978 mips_sll (code, dreg, dreg, 24);
2979 mips_sra (code, dreg, dreg, 24);
2981 else if (size == 2) {
2982 mips_sll (code, dreg, dreg, 16);
2983 mips_sra (code, dreg, dreg, 16);
2990 * emit_load_volatile_arguments:
2992 * Load volatile arguments from the stack to the original input registers.
2993 * Required before a tail call.
2996 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
2998 MonoMethod *method = cfg->method;
2999 MonoMethodSignature *sig;
3004 sig = mono_method_signature (method);
3005 cinfo = calculate_sizes (sig, sig->pinvoke);
3006 if (cinfo->struct_ret) {
3007 ArgInfo *ainfo = &cinfo->ret;
3008 inst = cfg->vret_addr;
3009 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3012 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3013 ArgInfo *ainfo = cinfo->args + i;
3014 inst = cfg->args [i];
3015 if (inst->opcode == OP_REGVAR) {
3016 if (ainfo->regtype == RegTypeGeneral)
3017 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3018 else if (ainfo->regtype == RegTypeFP)
3019 g_assert_not_reached();
3020 else if (ainfo->regtype == RegTypeBase) {
3023 g_assert_not_reached ();
3025 if (ainfo->regtype == RegTypeGeneral) {
3026 g_assert (mips_is_imm16 (inst->inst_offset));
3027 switch (ainfo->size) {
3029 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3032 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3036 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3039 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3040 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3043 g_assert_not_reached ();
3046 } else if (ainfo->regtype == RegTypeBase) {
3048 } else if (ainfo->regtype == RegTypeFP) {
3049 g_assert (mips_is_imm16 (inst->inst_offset));
3050 if (ainfo->size == 8) {
3051 #if _MIPS_SIM == _ABIO32
3052 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
3053 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
3054 #elif _MIPS_SIM == _ABIN32
3055 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3058 else if (ainfo->size == 4)
3059 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3061 g_assert_not_reached ();
3062 } else if (ainfo->regtype == RegTypeStructByVal) {
3064 int doffset = inst->inst_offset;
3066 g_assert (mips_is_imm16 (inst->inst_offset));
3067 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3068 for (i = 0; i < ainfo->size; ++i) {
3069 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3070 doffset += SIZEOF_REGISTER;
3072 } else if (ainfo->regtype == RegTypeStructByAddr) {
3073 g_assert (mips_is_imm16 (inst->inst_offset));
3074 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3076 g_assert_not_reached ();
3086 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3088 int size = cfg->param_area;
3090 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3091 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3096 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3097 if (ppc_is_imm16 (-size)) {
3098 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3100 ppc_load (code, ppc_r11, -size);
3101 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3108 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3110 int size = cfg->param_area;
3112 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3113 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3118 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3119 if (ppc_is_imm16 (size)) {
3120 ppc_stwu (code, ppc_r0, size, ppc_sp);
3122 ppc_load (code, ppc_r11, size);
3123 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3130 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3135 guint8 *code = cfg->native_code + cfg->code_len;
3136 MonoInst *last_ins = NULL;
3137 guint last_offset = 0;
3141 /* we don't align basic blocks of loops on mips */
3143 if (cfg->verbose_level > 2)
3144 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3146 cpos = bb->max_offset;
3149 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3150 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3151 g_assert (!mono_compile_aot);
3154 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3155 /* this is not thread save, but good enough */
3156 /* fixme: howto handle overflows? */
3157 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3158 mips_lw (code, mips_temp, mips_at, 0);
3159 mips_addiu (code, mips_temp, mips_temp, 1);
3160 mips_sw (code, mips_temp, mips_at, 0);
3163 MONO_BB_FOR_EACH_INS (bb, ins) {
3164 offset = code - cfg->native_code;
3166 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3168 if (offset > (cfg->code_size - max_len - 16)) {
3169 cfg->code_size *= 2;
3170 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3171 code = cfg->native_code + offset;
3173 mono_debug_record_line_number (cfg, ins, offset);
3174 if (cfg->verbose_level > 2) {
3175 g_print (" @ 0x%x\t", offset);
3176 mono_print_ins_index (ins_cnt++, ins);
3178 /* Check for virtual regs that snuck by */
3179 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3181 switch (ins->opcode) {
3182 case OP_RELAXED_NOP:
3185 case OP_DUMMY_STORE:
3186 case OP_NOT_REACHED:
3190 g_assert_not_reached();
3192 emit_tls_access (code, ins->dreg, ins->inst_offset);
3196 mips_mult (code, ins->sreg1, ins->sreg2);
3197 mips_mflo (code, ins->dreg);
3198 mips_mfhi (code, ins->dreg+1);
3201 mips_multu (code, ins->sreg1, ins->sreg2);
3202 mips_mflo (code, ins->dreg);
3203 mips_mfhi (code, ins->dreg+1);
3205 case OP_MEMORY_BARRIER:
3210 case OP_STOREI1_MEMBASE_IMM:
3211 mips_load_const (code, mips_temp, ins->inst_imm);
3212 if (mips_is_imm16 (ins->inst_offset)) {
3213 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3215 mips_load_const (code, mips_at, ins->inst_offset);
3216 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3219 case OP_STOREI2_MEMBASE_IMM:
3220 mips_load_const (code, mips_temp, ins->inst_imm);
3221 if (mips_is_imm16 (ins->inst_offset)) {
3222 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3224 mips_load_const (code, mips_at, ins->inst_offset);
3225 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3228 case OP_STOREI8_MEMBASE_IMM:
3229 mips_load_const (code, mips_temp, ins->inst_imm);
3230 if (mips_is_imm16 (ins->inst_offset)) {
3231 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3233 mips_load_const (code, mips_at, ins->inst_offset);
3234 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3237 case OP_STORE_MEMBASE_IMM:
3238 case OP_STOREI4_MEMBASE_IMM:
3239 mips_load_const (code, mips_temp, ins->inst_imm);
3240 if (mips_is_imm16 (ins->inst_offset)) {
3241 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3243 mips_load_const (code, mips_at, ins->inst_offset);
3244 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3247 case OP_STOREI1_MEMBASE_REG:
3248 if (mips_is_imm16 (ins->inst_offset)) {
3249 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3251 mips_load_const (code, mips_at, ins->inst_offset);
3252 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3253 mips_sb (code, ins->sreg1, mips_at, 0);
3256 case OP_STOREI2_MEMBASE_REG:
3257 if (mips_is_imm16 (ins->inst_offset)) {
3258 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3260 mips_load_const (code, mips_at, ins->inst_offset);
3261 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3262 mips_sh (code, ins->sreg1, mips_at, 0);
3265 case OP_STORE_MEMBASE_REG:
3266 case OP_STOREI4_MEMBASE_REG:
3267 if (mips_is_imm16 (ins->inst_offset)) {
3268 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3270 mips_load_const (code, mips_at, ins->inst_offset);
3271 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3272 mips_sw (code, ins->sreg1, mips_at, 0);
3275 case OP_STOREI8_MEMBASE_REG:
3276 if (mips_is_imm16 (ins->inst_offset)) {
3277 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3279 mips_load_const (code, mips_at, ins->inst_offset);
3280 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3281 mips_sd (code, ins->sreg1, mips_at, 0);
3285 g_assert_not_reached ();
3286 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3287 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3289 case OP_LOADI8_MEMBASE:
3290 if (mips_is_imm16 (ins->inst_offset)) {
3291 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3293 mips_load_const (code, mips_at, ins->inst_offset);
3294 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3295 mips_ld (code, ins->dreg, mips_at, 0);
3298 case OP_LOAD_MEMBASE:
3299 case OP_LOADI4_MEMBASE:
3300 case OP_LOADU4_MEMBASE:
3301 g_assert (ins->dreg != -1);
3302 if (mips_is_imm16 (ins->inst_offset)) {
3303 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3305 mips_load_const (code, mips_at, ins->inst_offset);
3306 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3307 mips_lw (code, ins->dreg, mips_at, 0);
3310 case OP_LOADI1_MEMBASE:
3311 if (mips_is_imm16 (ins->inst_offset)) {
3312 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3314 mips_load_const (code, mips_at, ins->inst_offset);
3315 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3316 mips_lb (code, ins->dreg, mips_at, 0);
3319 case OP_LOADU1_MEMBASE:
3320 if (mips_is_imm16 (ins->inst_offset)) {
3321 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3323 mips_load_const (code, mips_at, ins->inst_offset);
3324 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3325 mips_lbu (code, ins->dreg, mips_at, 0);
3328 case OP_LOADI2_MEMBASE:
3329 if (mips_is_imm16 (ins->inst_offset)) {
3330 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3332 mips_load_const (code, mips_at, ins->inst_offset);
3333 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3334 mips_lh (code, ins->dreg, mips_at, 0);
3337 case OP_LOADU2_MEMBASE:
3338 if (mips_is_imm16 (ins->inst_offset)) {
3339 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3341 mips_load_const (code, mips_at, ins->inst_offset);
3342 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3343 mips_lhu (code, ins->dreg, mips_at, 0);
3346 case OP_ICONV_TO_I1:
3347 mips_sll (code, mips_at, ins->sreg1, 24);
3348 mips_sra (code, ins->dreg, mips_at, 24);
3350 case OP_ICONV_TO_I2:
3351 mips_sll (code, mips_at, ins->sreg1, 16);
3352 mips_sra (code, ins->dreg, mips_at, 16);
3354 case OP_ICONV_TO_U1:
3355 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3357 case OP_ICONV_TO_U2:
3358 mips_sll (code, mips_at, ins->sreg1, 16);
3359 mips_srl (code, ins->dreg, mips_at, 16);
3362 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3365 g_assert (mips_is_imm16 (ins->inst_imm));
3366 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3369 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3372 g_assert (mips_is_imm16 (ins->inst_imm));
3373 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3376 mips_break (code, 0xfd);
3379 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3382 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3387 g_assert (mips_is_imm16 (ins->inst_imm));
3388 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3391 g_assert (mips_is_imm16 (ins->inst_imm));
3392 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3396 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3399 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3404 // we add the negated value
3405 g_assert (mips_is_imm16 (-ins->inst_imm));
3406 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3410 // we add the negated value
3411 g_assert (mips_is_imm16 (-ins->inst_imm));
3412 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3417 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3423 g_assert (!(ins->inst_imm & 0xffff0000));
3424 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3429 guint32 *divisor_is_m1;
3430 guint32 *dividend_is_minvalue;
3431 guint32 *divisor_is_zero;
3433 mips_load_const (code, mips_at, -1);
3434 divisor_is_m1 = (guint32 *)(void *)code;
3435 mips_bne (code, ins->sreg2, mips_at, 0);
3436 mips_lui (code, mips_at, mips_zero, 0x8000);
3437 dividend_is_minvalue = (guint32 *)(void *)code;
3438 mips_bne (code, ins->sreg1, mips_at, 0);
3441 /* Divide Int32.MinValue by -1 -- throw exception */
3442 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3444 mips_patch (divisor_is_m1, (guint32)code);
3445 mips_patch (dividend_is_minvalue, (guint32)code);
3447 /* Put divide in branch delay slot (NOT YET) */
3448 divisor_is_zero = (guint32 *)(void *)code;
3449 mips_bne (code, ins->sreg2, mips_zero, 0);
3452 /* Divide by zero -- throw exception */
3453 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3455 mips_patch (divisor_is_zero, (guint32)code);
3456 mips_div (code, ins->sreg1, ins->sreg2);
3457 if (ins->opcode == OP_IDIV)
3458 mips_mflo (code, ins->dreg);
3460 mips_mfhi (code, ins->dreg);
3465 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3467 /* Put divide in branch delay slot (NOT YET) */
3468 mips_bne (code, ins->sreg2, mips_zero, 0);
3471 /* Divide by zero -- throw exception */
3472 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3474 mips_patch (divisor_is_zero, (guint32)code);
3475 mips_divu (code, ins->sreg1, ins->sreg2);
3476 if (ins->opcode == OP_IDIV_UN)
3477 mips_mflo (code, ins->dreg);
3479 mips_mfhi (code, ins->dreg);
3483 g_assert_not_reached ();
3485 ppc_load (code, ppc_r11, ins->inst_imm);
3486 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3487 ppc_mfspr (code, ppc_r0, ppc_xer);
3488 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3489 /* FIXME: use OverflowException for 0x80000000/-1 */
3490 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3492 g_assert_not_reached();
3495 g_assert_not_reached ();
3497 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3501 g_assert (!(ins->inst_imm & 0xffff0000));
3502 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3505 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3509 /* unsigned 16-bit immediate */
3510 g_assert (!(ins->inst_imm & 0xffff0000));
3511 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3514 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3518 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3521 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3524 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3528 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3531 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3534 case OP_ISHR_UN_IMM:
3535 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3537 case OP_LSHR_UN_IMM:
3538 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3541 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3544 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3548 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3551 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3554 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3558 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3560 mips_mult (code, ins->sreg1, ins->sreg2);
3561 mips_mflo (code, ins->dreg);
3566 #if SIZEOF_REGISTER == 8
3568 mips_dmult (code, ins->sreg1, ins->sreg2);
3569 mips_mflo (code, ins->dreg);
3574 mips_mult (code, ins->sreg1, ins->sreg2);
3575 mips_mflo (code, ins->dreg);
3576 mips_mfhi (code, mips_at);
3579 mips_sra (code, mips_temp, ins->dreg, 31);
3580 patch = (guint32 *)(void *)code;
3581 mips_beq (code, mips_temp, mips_at, 0);
3583 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3584 mips_patch (patch, (guint32)code);
3587 case OP_IMUL_OVF_UN: {
3589 mips_mult (code, ins->sreg1, ins->sreg2);
3590 mips_mflo (code, ins->dreg);
3591 mips_mfhi (code, mips_at);
3594 patch = (guint32 *)(void *)code;
3595 mips_beq (code, mips_at, mips_zero, 0);
3597 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3598 mips_patch (patch, (guint32)code);
3602 mips_load_const (code, ins->dreg, ins->inst_c0);
3604 #if SIZEOF_REGISTER == 8
3606 mips_load_const (code, ins->dreg, ins->inst_c0);
3610 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3611 mips_load (code, ins->dreg, 0);
3615 mips_mtc1 (code, ins->dreg, ins->sreg1);
3617 case OP_MIPS_MTC1S_2:
3618 mips_mtc1 (code, ins->dreg, ins->sreg1);
3619 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3622 mips_mfc1 (code, ins->dreg, ins->sreg1);
3625 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3629 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3631 mips_mfc1 (code, ins->dreg+1, ins->sreg1);
3632 mips_mfc1 (code, ins->dreg, ins->sreg1+1);
3636 case OP_ICONV_TO_I4:
3637 case OP_ICONV_TO_U4:
3639 if (ins->dreg != ins->sreg1)
3640 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3642 #if SIZEOF_REGISTER == 8
3644 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3645 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3648 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3649 mips_dsra (code, ins->dreg, ins->dreg, 32);
3653 /* Get sreg1 into v1, sreg2 into v0 */
3655 if (ins->sreg1 == mips_v0) {
3656 if (ins->sreg1 != mips_at)
3657 MIPS_MOVE (code, mips_at, ins->sreg1);
3658 if (ins->sreg2 != mips_v0)
3659 MIPS_MOVE (code, mips_v0, ins->sreg2);
3660 MIPS_MOVE (code, mips_v1, mips_at);
3663 if (ins->sreg2 != mips_v0)
3664 MIPS_MOVE (code, mips_v0, ins->sreg2);
3665 if (ins->sreg1 != mips_v1)
3666 MIPS_MOVE (code, mips_v1, ins->sreg1);
3670 if (ins->dreg != ins->sreg1) {
3671 mips_fmovd (code, ins->dreg, ins->sreg1);
3675 /* Convert from double to float and leave it there */
3676 mips_cvtsd (code, ins->dreg, ins->sreg1);
3678 case OP_FCONV_TO_R4:
3680 mips_cvtsd (code, ins->dreg, ins->sreg1);
3682 /* Just a move, no precision change */
3683 if (ins->dreg != ins->sreg1) {
3684 mips_fmovd (code, ins->dreg, ins->sreg1);
3689 code = emit_load_volatile_arguments(cfg, code);
3692 * Pop our stack, then jump to specified method (tail-call)
3693 * Keep in sync with mono_arch_emit_epilog
3695 code = mono_arch_emit_epilog_sub (cfg, code);
3697 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3698 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3699 if (cfg->arch.long_branch) {
3700 mips_lui (code, mips_t9, mips_zero, 0);
3701 mips_addiu (code, mips_t9, mips_t9, 0);
3702 mips_jr (code, mips_t9);
3706 mips_beq (code, mips_zero, mips_zero, 0);
3711 /* ensure ins->sreg1 is not NULL */
3712 mips_lw (code, mips_zero, ins->sreg1, 0);
3715 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3716 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3718 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
3719 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
3721 mips_sw (code, mips_at, ins->sreg1, 0);
3734 case OP_VOIDCALL_REG:
3736 case OP_FCALL_MEMBASE:
3737 case OP_LCALL_MEMBASE:
3738 case OP_VCALL_MEMBASE:
3739 case OP_VCALL2_MEMBASE:
3740 case OP_VOIDCALL_MEMBASE:
3741 case OP_CALL_MEMBASE:
3742 call = (MonoCallInst*)ins;
3743 switch (ins->opcode) {
3750 if (ins->flags & MONO_INST_HAS_METHOD) {
3751 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3752 mips_load (code, mips_t9, call->method);
3755 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3756 mips_load (code, mips_t9, call->fptr);
3758 mips_jalr (code, mips_t9, mips_ra);
3765 case OP_VOIDCALL_REG:
3767 MIPS_MOVE (code, mips_t9, ins->sreg1);
3768 mips_jalr (code, mips_t9, mips_ra);
3771 case OP_FCALL_MEMBASE:
3772 case OP_LCALL_MEMBASE:
3773 case OP_VCALL_MEMBASE:
3774 case OP_VCALL2_MEMBASE:
3775 case OP_VOIDCALL_MEMBASE:
3776 case OP_CALL_MEMBASE:
3777 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3778 mips_jalr (code, mips_t9, mips_ra);
3782 #if PROMOTE_R4_TO_R8
3783 /* returned an FP R4 (single), promote to R8 (double) in place */
3784 if ((ins->opcode == OP_FCALL ||
3785 ins->opcode == OP_FCALL_REG) &&
3786 call->signature->ret->type == MONO_TYPE_R4) {
3787 mips_cvtds (code, mips_f0, mips_f0);
3792 int area_offset = cfg->param_area;
3794 /* Round up ins->sreg1, mips_at ends up holding size */
3795 mips_addiu (code, mips_at, ins->sreg1, 31);
3796 mips_addiu (code, mips_temp, mips_zero, ~31);
3797 mips_and (code, mips_at, mips_at, mips_temp);
3799 mips_subu (code, mips_sp, mips_sp, mips_at);
3800 g_assert (mips_is_imm16 (area_offset));
3801 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3803 if (ins->flags & MONO_INST_INIT) {
3804 mips_move (code, mips_temp, ins->dreg);
3805 mips_sb (code, mips_zero, mips_temp, 0);
3806 mips_addiu (code, mips_at, mips_at, -1);
3807 mips_bne (code, mips_at, mips_zero, -3);
3808 mips_addiu (code, mips_temp, mips_temp, 1);
3813 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3814 mips_move (code, mips_a0, ins->sreg1);
3815 mips_call (code, mips_t9, addr);
3816 mips_break (code, 0xfc);
3820 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3821 mips_move (code, mips_a0, ins->sreg1);
3822 mips_call (code, mips_t9, addr);
3823 mips_break (code, 0xfb);
3826 case OP_START_HANDLER: {
3828 * The START_HANDLER instruction marks the beginning of
3829 * a handler block. It is called using a call
3830 * instruction, so mips_ra contains the return address.
3831 * Since the handler executes in the same stack frame
3832 * as the method itself, we can't use save/restore to
3833 * save the return address. Instead, we save it into
3834 * a dedicated variable.
3836 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3837 g_assert (spvar->inst_basereg != mips_sp);
3838 code = emit_reserve_param_area (cfg, code);
3840 if (mips_is_imm16 (spvar->inst_offset)) {
3841 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3843 mips_load_const (code, mips_at, spvar->inst_offset);
3844 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3845 mips_sw (code, mips_ra, mips_at, 0);
3849 case OP_ENDFILTER: {
3850 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3851 g_assert (spvar->inst_basereg != mips_sp);
3852 code = emit_unreserve_param_area (cfg, code);
3854 if (ins->sreg1 != mips_v0)
3855 MIPS_MOVE (code, mips_v0, ins->sreg1);
3856 if (mips_is_imm16 (spvar->inst_offset)) {
3857 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3859 mips_load_const (code, mips_at, spvar->inst_offset);
3860 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3861 mips_lw (code, mips_ra, mips_at, 0);
3863 mips_jr (code, mips_ra);
3867 case OP_ENDFINALLY: {
3868 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3869 g_assert (spvar->inst_basereg != mips_sp);
3870 code = emit_unreserve_param_area (cfg, code);
3871 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3872 mips_jalr (code, mips_t9, mips_ra);
3876 case OP_CALL_HANDLER:
3877 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3878 mips_lui (code, mips_t9, mips_zero, 0);
3879 mips_addiu (code, mips_t9, mips_t9, 0);
3880 mips_jalr (code, mips_t9, mips_ra);
3882 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3883 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3886 ins->inst_c0 = code - cfg->native_code;
3889 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3890 if (cfg->arch.long_branch) {
3891 mips_lui (code, mips_at, mips_zero, 0);
3892 mips_addiu (code, mips_at, mips_at, 0);
3893 mips_jr (code, mips_at);
3897 mips_beq (code, mips_zero, mips_zero, 0);
3902 mips_jr (code, ins->sreg1);
3908 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3909 if (offset > (cfg->code_size - max_len - 16)) {
3910 cfg->code_size += max_len;
3911 cfg->code_size *= 2;
3912 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3913 code = cfg->native_code + offset;
3915 g_assert (ins->sreg1 != -1);
3916 mips_sll (code, mips_at, ins->sreg1, 2);
3917 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3918 MIPS_MOVE (code, mips_t8, mips_ra);
3919 mips_bgezal (code, mips_zero, 1); /* bal */
3921 mips_addu (code, mips_t9, mips_ra, mips_at);
3922 /* Table is 16 or 20 bytes from target of bal above */
3923 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3924 MIPS_MOVE (code, mips_ra, mips_t8);
3925 mips_lw (code, mips_t9, mips_t9, 20);
3928 mips_lw (code, mips_t9, mips_t9, 16);
3929 mips_jalr (code, mips_t9, mips_t8);
3931 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3932 mips_emit32 (code, 0xfefefefe);
3937 mips_addiu (code, ins->dreg, mips_zero, 1);
3938 mips_beq (code, mips_at, mips_zero, 2);
3940 MIPS_MOVE (code, ins->dreg, mips_zero);
3946 mips_addiu (code, ins->dreg, mips_zero, 1);
3947 mips_bltz (code, mips_at, 2);
3949 MIPS_MOVE (code, ins->dreg, mips_zero);
3955 mips_addiu (code, ins->dreg, mips_zero, 1);
3956 mips_bgtz (code, mips_at, 2);
3958 MIPS_MOVE (code, ins->dreg, mips_zero);
3961 case OP_MIPS_COND_EXC_EQ:
3962 case OP_MIPS_COND_EXC_GE:
3963 case OP_MIPS_COND_EXC_GT:
3964 case OP_MIPS_COND_EXC_LE:
3965 case OP_MIPS_COND_EXC_LT:
3966 case OP_MIPS_COND_EXC_NE_UN:
3967 case OP_MIPS_COND_EXC_GE_UN:
3968 case OP_MIPS_COND_EXC_GT_UN:
3969 case OP_MIPS_COND_EXC_LE_UN:
3970 case OP_MIPS_COND_EXC_LT_UN:
3972 case OP_MIPS_COND_EXC_OV:
3973 case OP_MIPS_COND_EXC_NO:
3974 case OP_MIPS_COND_EXC_C:
3975 case OP_MIPS_COND_EXC_NC:
3977 case OP_MIPS_COND_EXC_IEQ:
3978 case OP_MIPS_COND_EXC_IGE:
3979 case OP_MIPS_COND_EXC_IGT:
3980 case OP_MIPS_COND_EXC_ILE:
3981 case OP_MIPS_COND_EXC_ILT:
3982 case OP_MIPS_COND_EXC_INE_UN:
3983 case OP_MIPS_COND_EXC_IGE_UN:
3984 case OP_MIPS_COND_EXC_IGT_UN:
3985 case OP_MIPS_COND_EXC_ILE_UN:
3986 case OP_MIPS_COND_EXC_ILT_UN:
3988 case OP_MIPS_COND_EXC_IOV:
3989 case OP_MIPS_COND_EXC_INO:
3990 case OP_MIPS_COND_EXC_IC:
3991 case OP_MIPS_COND_EXC_INC: {
3995 /* If the condition is true, raise the exception */
3997 /* need to reverse test to skip around exception raising */
3999 /* For the moment, branch around a branch to avoid reversing
4002 /* Remember, an unpatched branch to 0 branches to the delay slot */
4003 switch (ins->opcode) {
4004 case OP_MIPS_COND_EXC_EQ:
4005 throw = (guint32 *)(void *)code;
4006 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4010 case OP_MIPS_COND_EXC_NE_UN:
4011 throw = (guint32 *)(void *)code;
4012 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4016 case OP_MIPS_COND_EXC_LE_UN:
4017 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4018 throw = (guint32 *)(void *)code;
4019 mips_beq (code, mips_at, mips_zero, 0);
4023 case OP_MIPS_COND_EXC_GT:
4024 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4025 throw = (guint32 *)(void *)code;
4026 mips_bne (code, mips_at, mips_zero, 0);
4030 case OP_MIPS_COND_EXC_GT_UN:
4031 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4032 throw = (guint32 *)(void *)code;
4033 mips_bne (code, mips_at, mips_zero, 0);
4037 case OP_MIPS_COND_EXC_LT:
4038 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4039 throw = (guint32 *)(void *)code;
4040 mips_bne (code, mips_at, mips_zero, 0);
4044 case OP_MIPS_COND_EXC_LT_UN:
4045 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4046 throw = (guint32 *)(void *)code;
4047 mips_bne (code, mips_at, mips_zero, 0);
4052 /* Not yet implemented */
4053 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4054 g_assert_not_reached ();
4056 skip = (guint32 *)(void *)code;
4057 mips_beq (code, mips_zero, mips_zero, 0);
4059 mips_patch (throw, (guint32)code);
4060 code = mips_emit_exc_by_name (code, ins->inst_p1);
4061 mips_patch (skip, (guint32)code);
4062 cfg->bb_exit->max_offset += 24;
4071 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4074 /* floating point opcodes */
4077 if (((guint32)ins->inst_p0) & (1 << 15))
4078 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4080 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4081 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4083 mips_load_const (code, mips_at, ins->inst_p0);
4084 mips_lwc1 (code, ins->dreg, mips_at, 4);
4085 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4089 if (((guint32)ins->inst_p0) & (1 << 15))
4090 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4092 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4093 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4094 #if PROMOTE_R4_TO_R8
4095 mips_cvtds (code, ins->dreg, ins->dreg);
4098 case OP_STORER8_MEMBASE_REG:
4099 if (mips_is_imm16 (ins->inst_offset)) {
4100 #if _MIPS_SIM == _ABIO32
4101 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
4102 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
4103 #elif _MIPS_SIM == _ABIN32
4104 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4107 mips_load_const (code, mips_at, ins->inst_offset);
4108 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4109 mips_swc1 (code, ins->sreg1, mips_at, 4);
4110 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
4113 case OP_LOADR8_MEMBASE:
4114 if (mips_is_imm16 (ins->inst_offset)) {
4115 #if _MIPS_SIM == _ABIO32
4116 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
4117 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
4118 #elif _MIPS_SIM == _ABIN32
4119 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4122 mips_load_const (code, mips_at, ins->inst_offset);
4123 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4124 mips_lwc1 (code, ins->dreg, mips_at, 4);
4125 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4128 case OP_STORER4_MEMBASE_REG:
4129 g_assert (mips_is_imm16 (ins->inst_offset));
4130 #if PROMOTE_R4_TO_R8
4131 /* Need to convert ins->sreg1 to single-precision first */
4132 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4133 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4135 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4139 g_assert (mips_is_imm16 (ins->inst_offset));
4140 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4142 case OP_LOADR4_MEMBASE:
4143 g_assert (mips_is_imm16 (ins->inst_offset));
4144 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4145 #if PROMOTE_R4_TO_R8
4146 /* Convert to double precision in place */
4147 mips_cvtds (code, ins->dreg, ins->dreg);
4150 case OP_LOADR4_MEMINDEX:
4151 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4152 mips_lwc1 (code, ins->dreg, mips_at, 0);
4154 case OP_LOADR8_MEMINDEX:
4155 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4156 #if _MIPS_SIM == _ABIO32
4157 mips_lwc1 (code, ins->dreg, mips_at, 0);
4158 mips_lwc1 (code, ins->dreg+1, mips_at, 4);
4159 #elif _MIPS_SIM == _ABIN32
4160 mips_ldc1 (code, ins->dreg, mips_at, 0);
4163 case OP_STORER4_MEMINDEX:
4164 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4165 #if PROMOTE_R4_TO_R8
4166 /* Need to convert ins->sreg1 to single-precision first */
4167 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4168 mips_swc1 (code, mips_ftemp, mips_at, 0);
4170 mips_swc1 (code, ins->sreg1, mips_at, 0);
4173 case OP_STORER8_MEMINDEX:
4174 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4175 #if _MIPS_SIM == _ABIO32
4176 mips_swc1 (code, ins->sreg1, mips_at, 0);
4177 mips_swc1 (code, ins->sreg1+1, mips_at, 4);
4178 #elif _MIPS_SIM == _ABIN32
4179 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4182 case OP_ICONV_TO_R_UN: {
4183 static const guint64 adjust_val = 0x41F0000000000000ULL;
4185 /* convert unsigned int to double */
4186 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4187 mips_bgez (code, ins->sreg1, 5);
4188 mips_cvtdw (code, ins->dreg, mips_ftemp);
4190 mips_load (code, mips_at, (guint32) &adjust_val);
4191 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4192 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4193 /* target is here */
4196 case OP_ICONV_TO_R4:
4197 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4198 mips_cvtsw (code, ins->dreg, mips_ftemp);
4199 mips_cvtds (code, ins->dreg, ins->dreg);
4201 case OP_ICONV_TO_R8:
4202 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4203 mips_cvtdw (code, ins->dreg, mips_ftemp);
4205 case OP_FCONV_TO_I1:
4206 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4208 case OP_FCONV_TO_U1:
4209 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4211 case OP_FCONV_TO_I2:
4212 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4214 case OP_FCONV_TO_U2:
4215 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4217 case OP_FCONV_TO_I4:
4219 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4221 case OP_FCONV_TO_U4:
4223 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4226 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4229 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4232 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4235 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4238 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4241 mips_fnegd (code, ins->dreg, ins->sreg1);
4244 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4245 mips_addiu (code, ins->dreg, mips_zero, 1);
4246 mips_fbtrue (code, 2);
4248 MIPS_MOVE (code, ins->dreg, mips_zero);
4251 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4252 mips_addiu (code, ins->dreg, mips_zero, 1);
4253 mips_fbtrue (code, 2);
4255 MIPS_MOVE (code, ins->dreg, mips_zero);
4258 /* Less than, or Unordered */
4259 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4260 mips_addiu (code, ins->dreg, mips_zero, 1);
4261 mips_fbtrue (code, 2);
4263 MIPS_MOVE (code, ins->dreg, mips_zero);
4266 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4267 MIPS_MOVE (code, ins->dreg, mips_zero);
4268 mips_fbtrue (code, 2);
4270 mips_addiu (code, ins->dreg, mips_zero, 1);
4273 /* Greater than, or Unordered */
4274 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4275 MIPS_MOVE (code, ins->dreg, mips_zero);
4276 mips_fbtrue (code, 2);
4278 mips_addiu (code, ins->dreg, mips_zero, 1);
4281 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4283 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4284 mips_fbtrue (code, 0);
4288 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4290 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4291 mips_fbfalse (code, 0);
4295 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4297 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4298 mips_fbtrue (code, 0);
4301 case OP_MIPS_FBLT_UN:
4302 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4304 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4305 mips_fbtrue (code, 0);
4309 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
4311 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4312 mips_fbfalse (code, 0);
4315 case OP_MIPS_FBGT_UN:
4316 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4318 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4319 mips_fbfalse (code, 0);
4323 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4325 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4326 mips_fbfalse (code, 0);
4329 case OP_MIPS_FBGE_UN:
4330 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
4332 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4333 mips_fbfalse (code, 0);
4337 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4339 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4340 mips_fbtrue (code, 0);
4343 case OP_MIPS_FBLE_UN:
4344 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4346 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4347 mips_fbtrue (code, 0);
4351 guint32 *branch_patch;
4353 mips_mfc1 (code, mips_at, ins->sreg1+1);
4354 mips_srl (code, mips_at, mips_at, 16+4);
4355 mips_andi (code, mips_at, mips_at, 2047);
4356 mips_addiu (code, mips_at, mips_at, -2047);
4358 branch_patch = (guint32 *)(void *)code;
4359 mips_bne (code, mips_at, mips_zero, 0);
4362 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4363 mips_patch (branch_patch, (guint32)code);
4364 mips_fmovd (code, ins->dreg, ins->sreg1);
4368 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4369 mips_load (code, ins->dreg, 0x0f0f0f0f);
4374 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4375 g_assert_not_reached ();
4378 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4379 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4380 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4381 g_assert_not_reached ();
4387 last_offset = offset;
4390 cfg->code_len = code - cfg->native_code;
4394 mono_arch_register_lowlevel_calls (void)
4399 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4401 MonoJumpInfo *patch_info;
4403 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4404 unsigned char *ip = patch_info->ip.i + code;
4405 const unsigned char *target = NULL;
4407 switch (patch_info->type) {
4408 case MONO_PATCH_INFO_IP:
4409 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4411 case MONO_PATCH_INFO_SWITCH: {
4412 gpointer *table = (gpointer *)patch_info->data.table->table;
4415 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4417 for (i = 0; i < patch_info->data.table->table_size; i++) {
4418 table [i] = (int)patch_info->data.table->table [i] + code;
4422 case MONO_PATCH_INFO_METHODCONST:
4423 case MONO_PATCH_INFO_CLASS:
4424 case MONO_PATCH_INFO_IMAGE:
4425 case MONO_PATCH_INFO_FIELD:
4426 case MONO_PATCH_INFO_VTABLE:
4427 case MONO_PATCH_INFO_IID:
4428 case MONO_PATCH_INFO_SFLDA:
4429 case MONO_PATCH_INFO_LDSTR:
4430 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4431 case MONO_PATCH_INFO_LDTOKEN:
4432 case MONO_PATCH_INFO_R4:
4433 case MONO_PATCH_INFO_R8:
4434 /* from OP_AOTCONST : lui + addiu */
4435 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4436 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4439 case MONO_PATCH_INFO_EXC_NAME:
4440 g_assert_not_reached ();
4441 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4444 case MONO_PATCH_INFO_NONE:
4445 /* everything is dealt with at epilog output time */
4448 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4449 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4458 mono_trace_lmf_prolog (MonoLMF *new_lmf)
4464 mono_trace_lmf_epilog (MonoLMF *old_lmf)
4470 * Allow tracing to work with this interface (with an optional argument)
4472 * This code is expected to be inserted just after the 'real' prolog code,
4473 * and before the first basic block. We need to allocate a 2nd, temporary
4474 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4478 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4481 int offset = cfg->arch.tracing_offset;
4487 /* For N32, need to know for each stack slot if it's an integer
4488 * or float argument, and save/restore the appropriate register
4490 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4491 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4492 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4493 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4494 #if _MIPS_SIM == _ABIN32
4495 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4496 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4497 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4498 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4501 mips_load_const (code, mips_a0, cfg->method);
4502 mips_addiu (code, mips_a1, mips_sp, offset);
4503 mips_call (code, mips_t9, func);
4505 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4506 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4507 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4508 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4509 #if _MIPS_SIM == _ABIN32
4510 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4511 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4512 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4513 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4523 mips_adjust_stackframe(MonoCompile *cfg)
4526 int delta, threshold, i;
4527 MonoMethodSignature *sig;
4530 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4533 /* adjust cfg->stack_offset for account for down-spilling */
4534 cfg->stack_offset += SIZEOF_REGISTER;
4536 /* re-align cfg->stack_offset if needed (due to var spilling) */
4537 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4538 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4539 if (cfg->verbose_level > 2) {
4540 g_print ("mips_adjust_stackframe:\n");
4541 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4543 threshold = cfg->arch.local_alloc_offset;
4544 ra_offset = cfg->stack_offset - sizeof(gpointer);
4545 if (cfg->verbose_level > 2) {
4546 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4549 sig = mono_method_signature (cfg->method);
4550 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4551 cfg->vret_addr->inst_offset += delta;
4553 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4554 MonoInst *inst = cfg->args [i];
4556 inst->inst_offset += delta;
4560 * loads and stores based off the frame reg that (used to) lie
4561 * above the spill var area need to be increased by 'delta'
4562 * to make room for the spill vars.
4564 /* Need to find loads and stores to adjust that
4565 * are above where the spillvars were inserted, but
4566 * which are not the spillvar references themselves.
4568 * Idea - since all offsets from fp are positive, make
4569 * spillvar offsets negative to begin with so we can spot
4574 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4578 if (cfg->verbose_level > 2) {
4579 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4581 MONO_BB_FOR_EACH_INS (bb, ins) {
4585 if (cfg->verbose_level > 2) {
4586 mono_print_ins_index (ins_cnt, ins);
4588 /* The == mips_sp tests catch FP spills */
4589 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4590 (ins->inst_basereg == mips_sp))) {
4591 switch (ins->opcode) {
4592 case OP_LOADI8_MEMBASE:
4593 case OP_LOADR8_MEMBASE:
4600 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4601 (ins->dreg == mips_sp))) {
4602 switch (ins->opcode) {
4603 case OP_STOREI8_MEMBASE_REG:
4604 case OP_STORER8_MEMBASE_REG:
4605 case OP_STOREI8_MEMBASE_IMM:
4613 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4616 if (ins->inst_c0 >= threshold) {
4617 ins->inst_c0 += delta;
4618 if (cfg->verbose_level > 2) {
4620 mono_print_ins_index (ins_cnt, ins);
4623 else if (ins->inst_c0 < 0) {
4624 /* Adj_c0 holds the size of the datatype. */
4625 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4626 if (cfg->verbose_level > 2) {
4628 mono_print_ins_index (ins_cnt, ins);
4631 g_assert (ins->inst_c0 != ra_offset);
4634 if (ins->inst_imm >= threshold) {
4635 ins->inst_imm += delta;
4636 if (cfg->verbose_level > 2) {
4638 mono_print_ins_index (ins_cnt, ins);
4641 g_assert (ins->inst_c0 != ra_offset);
4651 * Stack frame layout:
4653 * ------------------- sp + cfg->stack_usage + cfg->param_area
4654 * param area incoming
4655 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4657 * ------------------- sp + cfg->stack_usage
4659 * ------------------- sp + cfg->stack_usage-4
4661 * ------------------- sp +
4662 * MonoLMF structure optional
4663 * ------------------- sp + cfg->arch.lmf_offset
4664 * saved registers s0-s8
4665 * ------------------- sp + cfg->arch.iregs_offset
4667 * ------------------- sp + cfg->param_area
4668 * param area outgoing
4669 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4671 * ------------------- sp
4675 mono_arch_emit_prolog (MonoCompile *cfg)
4677 MonoMethod *method = cfg->method;
4678 MonoMethodSignature *sig;
4680 int alloc_size, pos, i;
4681 int alloc2_size = 0;
4685 guint32 iregs_to_save = 0;
4687 guint32 fregs_to_save = 0;
4690 /* lmf_offset is the offset of the LMF from our stack pointer. */
4691 guint32 lmf_offset = cfg->arch.lmf_offset;
4694 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4698 cfg->flags |= MONO_CFG_HAS_CALLS;
4700 sig = mono_method_signature (method);
4701 cfg->code_size = 768 + sig->param_count * 20;
4702 code = cfg->native_code = g_malloc (cfg->code_size);
4705 #if _MIPS_SIM == _ABIO32
4706 cfg->arch.tracing_offset = cfg->stack_offset;
4707 #elif _MIPS_SIM == _ABIN32
4708 /* no stack slots by default for argument regs, reserve a special block */
4709 cfg->arch.tracing_offset = cfg->stack_offset;
4710 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4714 /* adjust stackframe assignments for spillvars if needed */
4715 mips_adjust_stackframe (cfg);
4717 /* stack_offset should not be changed here. */
4718 alloc_size = cfg->stack_offset;
4719 cfg->stack_usage = alloc_size;
4722 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4724 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4728 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4730 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4731 fregs_to_save |= (fregs_to_save << 1);
4734 /* If the stack size is too big, save 1024 bytes to start with
4735 * so the prologue can use imm16(reg) addressing, then allocate
4736 * the rest of the frame.
4738 if (alloc_size > ((1 << 15) - 1024)) {
4739 alloc2_size = alloc_size - 1024;
4743 g_assert (mips_is_imm16 (-alloc_size));
4744 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4747 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4748 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4749 if (mips_is_imm16(offset))
4750 mips_sw (code, mips_ra, mips_sp, offset);
4752 g_assert_not_reached ();
4756 /* XXX - optimize this later to not save all regs if LMF constructed */
4757 pos = cfg->arch.iregs_offset - alloc2_size;
4759 if (iregs_to_save) {
4760 /* save used registers in own stack frame (at pos) */
4761 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4762 if (iregs_to_save & (1 << i)) {
4763 g_assert (pos < cfg->stack_usage - sizeof(gpointer));
4764 g_assert (mips_is_imm16(pos));
4765 MIPS_SW (code, i, mips_sp, pos);
4766 pos += SIZEOF_REGISTER;
4771 if (method->save_lmf) {
4772 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4773 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4774 g_assert (mips_is_imm16(offset));
4775 MIPS_SW (code, i, mips_sp, offset);
4781 /* Save float registers */
4782 if (fregs_to_save) {
4783 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4784 if (fregs_to_save & (1 << i)) {
4785 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4786 g_assert (mips_is_imm16(pos));
4787 mips_swc1 (code, i, mips_sp, pos);
4788 pos += sizeof (gulong);
4793 if (method->save_lmf) {
4794 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4795 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4796 g_assert (mips_is_imm16(offset));
4797 mips_swc1 (code, i, mips_sp, offset);
4802 if (cfg->frame_reg != mips_sp) {
4803 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4805 if (method->save_lmf) {
4806 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4807 g_assert (mips_is_imm16(offset));
4808 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4813 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
4814 * to the t* registers, which would be clobbered by the instrumentation calls.
4817 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4821 /* load arguments allocated to register from the stack */
4824 cinfo = calculate_sizes (sig, sig->pinvoke);
4826 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4827 ArgInfo *ainfo = &cinfo->ret;
4828 inst = cfg->vret_addr;
4829 if (inst->opcode == OP_REGVAR)
4830 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4831 else if (mips_is_imm16 (inst->inst_offset)) {
4832 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4834 mips_load_const (code, mips_at, inst->inst_offset);
4835 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4836 mips_sw (code, ainfo->reg, mips_at, 0);
4839 /* Keep this in sync with emit_load_volatile_arguments */
4840 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4841 ArgInfo *ainfo = cinfo->args + i;
4842 inst = cfg->args [pos];
4844 if (cfg->verbose_level > 2)
4845 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4846 if (inst->opcode == OP_REGVAR) {
4847 /* Argument ends up in a register */
4848 if (ainfo->regtype == RegTypeGeneral)
4849 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4850 else if (ainfo->regtype == RegTypeFP) {
4851 g_assert_not_reached();
4853 ppc_fmr (code, inst->dreg, ainfo->reg);
4856 else if (ainfo->regtype == RegTypeBase) {
4857 int offset = cfg->stack_usage + ainfo->offset;
4858 g_assert (mips_is_imm16(offset));
4859 mips_lw (code, inst->dreg, mips_sp, offset);
4861 g_assert_not_reached ();
4863 if (cfg->verbose_level > 2)
4864 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4866 /* Argument ends up on the stack */
4867 if (ainfo->regtype == RegTypeGeneral) {
4868 /* Incoming parameters should be above this frame */
4869 if (cfg->verbose_level > 2)
4870 g_print ("stack slot at %d of %d\n", inst->inst_offset, alloc_size);
4871 /* g_assert (inst->inst_offset >= alloc_size); */
4872 g_assert (mips_is_imm16 (inst->inst_offset));
4873 switch (ainfo->size) {
4875 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4878 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4882 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4885 #if (SIZEOF_REGISTER == 4)
4886 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4887 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
4888 #elif (SIZEOF_REGISTER == 8)
4889 mips_sd (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4893 g_assert_not_reached ();
4896 } else if (ainfo->regtype == RegTypeBase) {
4898 * Argument comes in on the stack, and ends up on the stack
4899 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4900 * 8 and 16 bit quantities. Shorten them in place.
4902 g_assert (mips_is_imm16 (inst->inst_offset));
4903 switch (ainfo->size) {
4905 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4906 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4909 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4910 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4917 g_assert_not_reached ();
4919 } else if (ainfo->regtype == RegTypeFP) {
4920 g_assert (mips_is_imm16 (inst->inst_offset));
4921 g_assert (mips_is_imm16 (inst->inst_offset+4));
4922 if (ainfo->size == 8) {
4923 #if _MIPS_SIM == _ABIO32
4924 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
4925 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
4926 #elif _MIPS_SIM == _ABIN32
4927 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4930 else if (ainfo->size == 4)
4931 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4933 g_assert_not_reached ();
4934 } else if (ainfo->regtype == RegTypeStructByVal) {
4936 int doffset = inst->inst_offset;
4938 g_assert (mips_is_imm16 (inst->inst_offset));
4939 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4940 /* Push the argument registers into their stack slots */
4941 for (i = 0; i < ainfo->size; ++i) {
4942 g_assert (mips_is_imm16(doffset));
4943 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
4944 doffset += SIZEOF_REGISTER;
4946 } else if (ainfo->regtype == RegTypeStructByAddr) {
4947 g_assert (mips_is_imm16 (inst->inst_offset));
4948 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4949 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4951 g_assert_not_reached ();
4956 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4957 mips_load_const (code, mips_a0, cfg->domain);
4958 mips_call (code, mips_t9, (gpointer)mono_jit_thread_attach);
4962 if (method->save_lmf) {
4963 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
4964 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
4966 if (lmf_pthread_key != -1) {
4967 g_assert_not_reached();
4969 emit_tls_access (code, mips_temp, lmf_pthread_key);
4971 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
4972 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
4973 g_assert (mips_is_imm16(offset));
4974 mips_addiu (code, mips_a0, mips_temp, offset);
4977 /* This can/will clobber the a0-a3 registers */
4978 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
4981 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4982 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
4983 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4984 /* new_lmf->previous_lmf = *lmf_addr */
4985 mips_lw (code, mips_at, mips_v0, 0);
4986 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
4987 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4988 /* *(lmf_addr) = sp + lmf_offset */
4989 g_assert (mips_is_imm16(lmf_offset));
4990 mips_addiu (code, mips_at, mips_sp, lmf_offset);
4991 mips_sw (code, mips_at, mips_v0, 0);
4993 /* save method info */
4994 mips_load_const (code, mips_at, method);
4995 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
4996 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
4997 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
4998 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
5000 /* save the current IP */
5001 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5002 mips_load_const (code, mips_at, 0x01010101);
5003 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5007 if (mips_is_imm16 (-alloc2_size)) {
5008 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5011 mips_load_const (code, mips_at, -alloc2_size);
5012 mips_addu (code, mips_sp, mips_sp, mips_at);
5014 if (cfg->frame_reg != mips_sp)
5015 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5016 alloc_size += alloc2_size;
5019 cfg->code_len = code - cfg->native_code;
5020 g_assert (cfg->code_len < cfg->code_size);
5035 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5038 int save_mode = SAVE_NONE;
5040 MonoMethod *method = cfg->method;
5041 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5042 int save_offset = MIPS_STACK_PARAM_OFFSET;
5044 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5046 offset = code - cfg->native_code;
5047 /* we need about 16 instructions */
5048 if (offset > (cfg->code_size - 16 * 4)) {
5049 cfg->code_size *= 2;
5050 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5051 code = cfg->native_code + offset;
5056 case MONO_TYPE_VOID:
5057 /* special case string .ctor icall */
5058 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5059 save_mode = SAVE_ONE;
5061 save_mode = SAVE_NONE;
5065 save_mode = SAVE_FP;
5067 case MONO_TYPE_VALUETYPE:
5068 save_mode = SAVE_STRUCT;
5072 #if SIZEOF_REGISTER == 4
5073 save_mode = SAVE_TWO;
5074 #elif SIZEOF_REGISTER == 8
5075 save_mode = SAVE_ONE;
5079 save_mode = SAVE_ONE;
5083 mips_addiu (code, mips_sp, mips_sp, -32);
5084 g_assert (mips_is_imm16(save_offset));
5085 switch (save_mode) {
5087 mips_sw (code, mips_v0, mips_sp, save_offset);
5088 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5089 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5090 if (enable_arguments) {
5091 MIPS_MOVE (code, mips_a1, mips_v0);
5092 MIPS_MOVE (code, mips_a2, mips_v1);
5096 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5097 if (enable_arguments) {
5098 MIPS_MOVE (code, mips_a1, mips_v0);
5102 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5103 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5104 mips_lw (code, mips_a0, mips_sp, save_offset);
5105 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5106 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5113 mips_load_const (code, mips_a0, cfg->method);
5114 mips_call (code, mips_t9, func);
5116 switch (save_mode) {
5118 mips_lw (code, mips_v0, mips_sp, save_offset);
5119 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5120 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5123 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5126 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5133 mips_addiu (code, mips_sp, mips_sp, 32);
5140 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5142 MonoMethod *method = cfg->method;
5144 int max_epilog_size = 16 + 20*4;
5145 int alloc2_size = 0;
5146 guint32 iregs_to_restore;
5148 guint32 fregs_to_restore;
5152 if (cfg->method->save_lmf)
5153 max_epilog_size += 128;
5156 if (mono_jit_trace_calls != NULL)
5157 max_epilog_size += 50;
5159 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5160 max_epilog_size += 50;
5163 pos = code - cfg->native_code;
5164 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5165 cfg->code_size *= 2;
5166 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5167 mono_jit_stats.code_reallocs++;
5171 * Keep in sync with OP_JMP
5174 code = cfg->native_code + pos;
5176 code = cfg->native_code + cfg->code_len;
5178 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5179 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5181 if (cfg->frame_reg != mips_sp) {
5182 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5184 /* If the stack frame is really large, deconstruct it in two steps */
5185 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5186 alloc2_size = cfg->stack_usage - 1024;
5187 /* partially deconstruct the stack */
5188 mips_load_const (code, mips_at, alloc2_size);
5189 mips_addu (code, mips_sp, mips_sp, mips_at);
5191 pos = cfg->arch.iregs_offset - alloc2_size;
5193 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5195 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5197 if (iregs_to_restore) {
5198 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5199 if (iregs_to_restore & (1 << i)) {
5200 g_assert (mips_is_imm16(pos));
5201 MIPS_LW (code, i, mips_sp, pos);
5202 pos += SIZEOF_REGISTER;
5209 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5211 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5212 fregs_to_restore |= (fregs_to_restore << 1);
5214 if (fregs_to_restore) {
5215 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5216 if (fregs_to_restore & (1 << i)) {
5217 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5218 g_assert (mips_is_imm16(pos));
5219 mips_lwc1 (code, i, mips_sp, pos);
5226 /* Unlink the LMF if necessary */
5227 if (method->save_lmf) {
5228 int lmf_offset = cfg->arch.lmf_offset;
5230 /* t0 = current_lmf->previous_lmf */
5231 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5232 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5234 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5235 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5236 /* (*lmf_addr) = previous_lmf */
5237 mips_sw (code, mips_temp, mips_t1, 0);
5241 /* Restore the fp */
5242 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5245 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5246 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5247 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5249 /* Restore the stack pointer */
5250 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5251 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5253 /* Caller will emit either return or tail-call sequence */
5255 cfg->code_len = code - cfg->native_code;
5257 g_assert (cfg->code_len < cfg->code_size);
5262 mono_arch_emit_epilog (MonoCompile *cfg)
5266 code = mono_arch_emit_epilog_sub (cfg, NULL);
5268 mips_jr (code, mips_ra);
5271 cfg->code_len = code - cfg->native_code;
5273 g_assert (cfg->code_len < cfg->code_size);
5276 /* remove once throw_exception_by_name is eliminated */
5279 exception_id_by_name (const char *name)
5281 if (strcmp (name, "IndexOutOfRangeException") == 0)
5282 return MONO_EXC_INDEX_OUT_OF_RANGE;
5283 if (strcmp (name, "OverflowException") == 0)
5284 return MONO_EXC_OVERFLOW;
5285 if (strcmp (name, "ArithmeticException") == 0)
5286 return MONO_EXC_ARITHMETIC;
5287 if (strcmp (name, "DivideByZeroException") == 0)
5288 return MONO_EXC_DIVIDE_BY_ZERO;
5289 if (strcmp (name, "InvalidCastException") == 0)
5290 return MONO_EXC_INVALID_CAST;
5291 if (strcmp (name, "NullReferenceException") == 0)
5292 return MONO_EXC_NULL_REF;
5293 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5294 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5295 if (strcmp (name, "ArgumentException") == 0)
5296 return MONO_EXC_ARGUMENT;
5297 g_error ("Unknown intrinsic exception %s\n", name);
5303 mono_arch_emit_exceptions (MonoCompile *cfg)
5306 MonoJumpInfo *patch_info;
5309 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5310 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5311 int max_epilog_size = 50;
5313 /* count the number of exception infos */
5316 * make sure we have enough space for exceptions
5317 * 24 is the simulated call to throw_exception_by_name
5319 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5321 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5322 i = exception_id_by_name (patch_info->data.target);
5323 g_assert (i < MONO_EXC_INTRINS_NUM);
5324 if (!exc_throw_found [i]) {
5325 max_epilog_size += 12;
5326 exc_throw_found [i] = TRUE;
5332 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5333 cfg->code_size *= 2;
5334 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5335 mono_jit_stats.code_reallocs++;
5338 code = cfg->native_code + cfg->code_len;
5340 /* add code to raise exceptions */
5341 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5342 switch (patch_info->type) {
5343 case MONO_PATCH_INFO_EXC: {
5345 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5347 i = exception_id_by_name (patch_info->data.target);
5348 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5349 if (!exc_throw_pos [i]) {
5352 exc_throw_pos [i] = code;
5353 //g_print ("exc: writing stub at %p\n", code);
5354 mips_load_const (code, mips_a0, patch_info->data.target);
5355 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5356 mips_load_const (code, mips_t9, addr);
5357 mips_jr (code, mips_t9);
5360 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5362 /* Turn into a Relative patch, pointing at code stub */
5363 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5364 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5366 g_assert_not_reached();
5376 cfg->code_len = code - cfg->native_code;
5378 g_assert (cfg->code_len < cfg->code_size);
5383 * Thread local storage support
5386 setup_tls_access (void)
5389 //guint32 *ins, *code;
5391 if (tls_mode == TLS_MODE_FAILED)
5394 if (g_getenv ("MONO_NO_TLS")) {
5395 tls_mode = TLS_MODE_FAILED;
5399 if (tls_mode == TLS_MODE_DETECT) {
5401 tls_mode = TLS_MODE_FAILED;
5405 ins = (guint32*)pthread_getspecific;
5406 /* uncond branch to the real method */
5407 if ((*ins >> 26) == 18) {
5409 val = (*ins & ~3) << 6;
5413 ins = (guint32*)val;
5415 ins = (guint32*) ((char*)ins + val);
5418 code = &cmplwi_1023;
5419 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5421 ppc_li (code, ppc_r4, 0x48);
5424 if (*ins == cmplwi_1023) {
5425 int found_lwz_284 = 0;
5426 for (ptk = 0; ptk < 20; ++ptk) {
5428 if (!*ins || *ins == blr_ins)
5430 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5435 if (!found_lwz_284) {
5436 tls_mode = TLS_MODE_FAILED;
5439 tls_mode = TLS_MODE_LTHREADS;
5440 } else if (*ins == li_0x48) {
5442 /* uncond branch to the real method */
5443 if ((*ins >> 26) == 18) {
5445 val = (*ins & ~3) << 6;
5449 ins = (guint32*)val;
5451 ins = (guint32*) ((char*)ins + val);
5454 ppc_li (code, ppc_r0, 0x7FF2);
5455 if (ins [1] == val) {
5456 /* Darwin on G4, implement */
5457 tls_mode = TLS_MODE_FAILED;
5461 ppc_mfspr (code, ppc_r3, 104);
5462 if (ins [1] != val) {
5463 tls_mode = TLS_MODE_FAILED;
5466 tls_mode = TLS_MODE_DARWIN_G5;
5469 tls_mode = TLS_MODE_FAILED;
5473 tls_mode = TLS_MODE_FAILED;
5478 if (monodomain_key == -1) {
5479 ptk = mono_domain_get_tls_key ();
5481 ptk = mono_pthread_key_for_tls (ptk);
5483 monodomain_key = ptk;
5487 if (lmf_pthread_key == -1) {
5488 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5490 /*g_print ("MonoLMF at: %d\n", ptk);*/
5491 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5492 init_tls_failed = 1;
5495 lmf_pthread_key = ptk;
5498 if (monothread_key == -1) {
5499 ptk = mono_thread_get_tls_key ();
5501 ptk = mono_pthread_key_for_tls (ptk);
5503 monothread_key = ptk;
5504 /*g_print ("thread inited: %d\n", ptk);*/
5507 /*g_print ("thread not inited yet %d\n", ptk);*/
5513 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5515 setup_tls_access ();
5519 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5524 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5526 int this_dreg = mips_a0;
5529 this_dreg = mips_a1;
5531 /* add the this argument */
5532 if (this_reg != -1) {
5534 MONO_INST_NEW (cfg, this, OP_MOVE);
5535 this->type = this_type;
5536 this->sreg1 = this_reg;
5537 this->dreg = mono_alloc_ireg (cfg);
5538 mono_bblock_add_inst (cfg->cbb, this);
5539 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5544 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5545 vtarg->type = STACK_MP;
5546 vtarg->sreg1 = vt_reg;
5547 vtarg->dreg = mono_alloc_ireg (cfg);
5548 mono_bblock_add_inst (cfg->cbb, vtarg);
5549 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5554 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5556 MonoInst *ins = NULL;
5562 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5568 mono_arch_print_tree (MonoInst *tree, int arity)
5573 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5577 setup_tls_access ();
5578 if (monodomain_key == -1)
5581 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5582 ins->inst_offset = monodomain_key;
5587 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5589 /* FIXME: implement */
5590 g_assert_not_reached ();
5593 #ifdef MONO_ARCH_HAVE_IMT
5595 #define ENABLE_WRONG_METHOD_CHECK 0
5597 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5598 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5600 #define LOADSTORE_SIZE 4
5601 #define JUMP_IMM_SIZE 16
5602 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5603 #define LOAD_CONST_SIZE 8
5604 #define JUMP_JR_SIZE 8
5607 * LOCKING: called with the domain lock held
5610 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5611 gpointer fail_tramp)
5615 guint8 *code, *start, *patch;
5617 for (i = 0; i < count; ++i) {
5618 MonoIMTCheckItem *item = imt_entries [i];
5620 if (item->is_equals) {
5621 if (item->check_target_idx) {
5622 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5623 if (item->has_target_code)
5624 item->chunk_size += LOAD_CONST_SIZE;
5626 item->chunk_size += LOADSTORE_SIZE;
5629 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5630 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5631 if (!item->has_target_code)
5632 item->chunk_size += LOADSTORE_SIZE;
5634 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5635 #if ENABLE_WRONG_METHOD_CHECK
5636 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5641 item->chunk_size += CMP_SIZE + BR_SIZE;
5642 imt_entries [item->check_target_idx]->compare_done = TRUE;
5644 size += item->chunk_size;
5646 /* the initial load of the vtable address */
5647 size += MIPS_LOAD_SEQUENCE_LENGTH;
5649 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5651 code = mono_domain_code_reserve (domain, size);
5657 * We need to save and restore r11 because it might be
5658 * used by the caller as the vtable register, so
5659 * clobbering it will trip up the magic trampoline.
5661 * FIXME: Get rid of this by making sure that r11 is
5662 * not used as the vtable register in interface calls.
5664 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5665 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5667 /* t7 points to the vtable */
5668 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5670 for (i = 0; i < count; ++i) {
5671 MonoIMTCheckItem *item = imt_entries [i];
5673 item->code_target = code;
5674 if (item->is_equals) {
5675 if (item->check_target_idx) {
5676 mips_load_const (code, mips_temp, (gsize)item->key);
5677 item->jmp_code = code;
5678 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5680 if (item->has_target_code) {
5681 mips_load_const (code, mips_t9,
5682 item->value.target_code);
5685 mips_lw (code, mips_t9, mips_t7,
5686 (sizeof (gpointer) * item->value.vtable_slot));
5688 mips_jr (code, mips_t9);
5692 mips_load_const (code, mips_temp, (gsize)item->key);
5694 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5696 if (item->has_target_code) {
5697 mips_load_const (code, mips_t9,
5698 item->value.target_code);
5701 mips_load_const (code, mips_at,
5702 & (vtable->vtable [item->value.vtable_slot]));
5703 mips_lw (code, mips_t9, mips_at, 0);
5705 mips_jr (code, mips_t9);
5707 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5708 mips_load_const (code, mips_at, fail_tramp);
5709 mips_lw (code, mips_t9, mips_at, 0);
5710 mips_jr (code, mips_t9);
5713 /* enable the commented code to assert on wrong method */
5714 #if ENABLE_WRONG_METHOD_CHECK
5715 ppc_load (code, ppc_r0, (guint32)item->key);
5716 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5718 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5720 mips_lw (code, mips_t9, mips_t7,
5721 (sizeof (gpointer) * item->value.vtable_slot));
5722 mips_jr (code, mips_t9);
5725 #if ENABLE_WRONG_METHOD_CHECK
5726 ppc_patch (patch, code);
5732 mips_load_const (code, mips_temp, (gulong)item->key);
5733 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5735 item->jmp_code = code;
5736 mips_beq (code, mips_temp, mips_zero, 0);
5740 /* patch the branches to get to the target items */
5741 for (i = 0; i < count; ++i) {
5742 MonoIMTCheckItem *item = imt_entries [i];
5743 if (item->jmp_code && item->check_target_idx) {
5744 mips_patch ((guint32 *)item->jmp_code,
5745 (guint32)imt_entries [item->check_target_idx]->code_target);
5750 mono_stats.imt_thunks_size += code - start;
5751 g_assert (code - start <= size);
5752 mono_arch_flush_icache (start, size);
5757 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5759 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5764 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5767 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];