2 * mini-mips.c: MIPS backend for the Mono code generator
5 * Mark Mason (mason@broadcom.com)
7 * Based on mini-ppc.c by
8 * Paolo Molaro (lupus@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2003 Ximian, Inc.
16 #include <asm/cachectl.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
21 #include <mono/arch/mips/mips-codegen.h>
23 #include "mini-mips.h"
28 #define SAVE_FP_REGS 0
29 #define SAVE_ALL_REGS 0
30 #define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
33 #define ALWAYS_USE_FP 1
34 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
36 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
37 #define USE_MUL 1 /* use mul instead of mult/mflo for multiply */
39 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
40 #define mips_call(c,D,v) do { \
41 guint32 _target = (guint32)(v); \
42 if (1 || !(v) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
43 mips_load_const (c, D, _target); \
44 mips_jalr (c, D, mips_ra); \
47 mips_jumpl (c, _target >> 2); \
59 /* This mutex protects architecture specific caches */
60 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
61 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
62 static CRITICAL_SECTION mini_arch_mutex;
64 int mono_exc_esp_offset = 0;
65 static int tls_mode = TLS_MODE_DETECT;
66 static int lmf_pthread_key = -1;
67 static int monothread_key = -1;
68 static int monodomain_key = -1;
71 #define DEBUG(a) if (cfg->verbose_level > 1) a
77 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
79 code = mips_emit_exc_by_name (code, exc_name); \
80 cfg->bb_exit->max_offset += 16; \
84 #define emit_linuxthreads_tls(code,dreg,key) do {\
86 off1 = offsets_from_pthread_key ((key), &off2); \
87 g_assert_not_reached (); \
88 ppc_lwz ((code), (dreg), off1, ppc_r2); \
89 ppc_lwz ((code), (dreg), off2, (dreg)); \
93 #define emit_tls_access(code,dreg,key) do { \
95 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
96 default: g_assert_not_reached (); \
100 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
102 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
103 inst->type = STACK_R8; \
105 inst->inst_p0 = (void*)(addr); \
106 mono_bblock_add_inst (cfg->cbb, inst); \
109 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
110 || ((ins)->opcode == OP_ICOMPARE) \
111 || ((ins)->opcode == OP_LCOMPARE)))
112 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
113 || ((ins)->opcode == OP_ICOMPARE_IMM) \
114 || ((ins)->opcode == OP_LCOMPARE_IMM)))
116 #define INS_REWRITE(ins, op, _s1, _s2) do { \
119 ins->opcode = (op); \
124 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
126 ins->opcode = (op); \
128 ins->inst_imm = (_imm); \
132 typedef struct InstList InstList;
150 guint16 vtsize; /* in param area */
152 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
153 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
162 gboolean vtype_retaddr;
171 void patch_lui_addiu(guint32 *ip, guint32 val);
172 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
173 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
174 void mips_adjust_stackframe(MonoCompile *cfg);
175 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
176 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
180 mono_arch_flush_icache (guint8 *code, gint size)
182 /* Linux/MIPS specific */
183 cacheflush (code, size, BCACHE);
187 mono_arch_flush_register_windows (void)
192 mono_arch_is_inst_imm (gint64 imm)
198 mips_emit_exc_by_name(guint8 *code, const char *name)
201 MonoClass *exc_class;
203 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
204 g_assert (exc_class);
206 mips_load_const (code, mips_a0, exc_class->type_token);
207 addr = (guint32) mono_get_throw_corlib_exception ();
208 mips_call (code, mips_t9, addr);
214 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
216 if (mips_is_imm16 (v))
217 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
219 #if SIZEOF_REGISTER == 8
221 /* v is not a sign-extended 32-bit value */
222 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
223 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
224 mips_dsll (code, dreg, dreg, 16);
225 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
226 mips_dsll (code, dreg, dreg, 16);
227 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
231 if (((guint32)v) & (1 << 15)) {
232 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
235 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
237 if (((guint32)v) & 0xffff)
238 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
244 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
247 if (cfg->arch.long_branch) {
250 /* Invert test and emit branch around jump */
253 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
257 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
261 mips_bltz (code, ins->sreg1, br_offset);
265 mips_blez (code, ins->sreg1, br_offset);
269 mips_bgtz (code, ins->sreg1, br_offset);
273 mips_bgez (code, ins->sreg1, br_offset);
277 g_assert_not_reached ();
279 mono_add_patch_info (cfg, code - cfg->native_code,
280 MONO_PATCH_INFO_BB, ins->inst_true_bb);
281 mips_lui (code, mips_at, mips_zero, 0);
282 mips_addiu (code, mips_at, mips_at, 0);
283 mips_jr (code, mips_at);
287 mono_add_patch_info (cfg, code - cfg->native_code,
288 MONO_PATCH_INFO_BB, ins->inst_true_bb);
291 mips_beq (code, ins->sreg1, ins->sreg2, 0);
295 mips_bne (code, ins->sreg1, ins->sreg2, 0);
299 mips_bgez (code, ins->sreg1, 0);
303 mips_bgtz (code, ins->sreg1, 0);
307 mips_blez (code, ins->sreg1, 0);
311 mips_bltz (code, ins->sreg1, 0);
315 g_assert_not_reached ();
321 /* XXX - big-endian dependent? */
323 patch_lui_addiu(guint32 *ip, guint32 val)
325 guint16 *__lui_addiu = (guint16*)(void *)(ip);
328 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
329 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
332 if (((guint32)(val)) & (1 << 15))
333 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
335 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
336 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
337 mono_arch_flush_icache ((guint8 *)ip, 8);
342 mips_patch (guint32 *code, guint32 target)
345 guint32 op = ins >> 26;
346 guint32 diff, offset;
348 g_assert (trap_target != target);
349 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
351 case 0x00: /* jr ra */
352 if (ins == 0x3e00008)
354 g_assert_not_reached ();
358 g_assert (!(target & 0x03));
359 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
360 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
362 mono_arch_flush_icache ((guint8 *)code, 4);
364 case 0x01: /* BLTZ */
367 case 0x06: /* BLEZ */
368 case 0x07: /* BGTZ */
369 case 0x11: /* bc1t */
370 diff = target - (guint32)(code + 1);
371 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
372 g_assert (!(diff & 0x03));
373 offset = ((gint32)diff) >> 2;
374 g_assert (((int)offset) == ((int)(short)offset));
375 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
377 mono_arch_flush_icache ((guint8 *)code, 4);
379 case 0x0f: /* LUI / ADDIU pair */
380 patch_lui_addiu (code, target);
381 mono_arch_flush_icache ((guint8 *)code, 8);
385 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
386 g_assert_not_reached ();
392 offsets_from_pthread_key (guint32 key, int *offset2)
396 *offset2 = idx2 * sizeof (gpointer);
397 return 284 + idx1 * sizeof (gpointer);
402 mono_arch_regname (int reg) {
403 #if _MIPS_SIM == _ABIO32
404 static const char * rnames[] = {
405 "zero", "at", "v0", "v1",
406 "a0", "a1", "a2", "a3",
407 "t0", "t1", "t2", "t3",
408 "t4", "t5", "t6", "t7",
409 "s0", "s1", "s2", "s3",
410 "s4", "s5", "s6", "s7",
411 "t8", "t9", "k0", "k1",
412 "gp", "sp", "fp", "ra"
414 #elif _MIPS_SIM == _ABIN32
415 static const char * rnames[] = {
416 "zero", "at", "v0", "v1",
417 "a0", "a1", "a2", "a3",
418 "a4", "a5", "a6", "a7",
419 "t0", "t1", "t2", "t3",
420 "s0", "s1", "s2", "s3",
421 "s4", "s5", "s6", "s7",
422 "t8", "t9", "k0", "k1",
423 "gp", "sp", "fp", "ra"
426 if (reg >= 0 && reg < 32)
432 mono_arch_fregname (int reg) {
433 static const char * rnames[] = {
434 "f0", "f1", "f2", "f3",
435 "f4", "f5", "f6", "f7",
436 "f8", "f9", "f10", "f11",
437 "f12", "f13", "f14", "f15",
438 "f16", "f17", "f18", "f19",
439 "f20", "f21", "f22", "f23",
440 "f24", "f25", "f26", "f27",
441 "f28", "f29", "f30", "f31"
443 if (reg >= 0 && reg < 32)
448 /* this function overwrites at */
450 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
452 /* XXX write a loop, not an unrolled loop */
454 mips_lw (code, mips_at, sreg, soffset);
455 mips_sw (code, mips_at, dreg, doffset);
464 * mono_arch_get_argument_info:
465 * @csig: a method signature
466 * @param_count: the number of parameters to consider
467 * @arg_info: an array to store the result infos
469 * Gathers information on parameters such as size, alignment and
470 * padding. arg_info should be large enought to hold param_count + 1 entries.
472 * Returns the size of the activation frame.
475 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
477 int k, frame_size = 0;
478 guint32 size, align, pad;
481 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
482 frame_size += sizeof (gpointer);
486 arg_info [0].offset = offset;
489 frame_size += sizeof (gpointer);
493 arg_info [0].size = frame_size;
495 for (k = 0; k < param_count; k++) {
496 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
498 /* ignore alignment for now */
501 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
502 arg_info [k].pad = pad;
504 arg_info [k + 1].pad = 0;
505 arg_info [k + 1].size = size;
507 arg_info [k + 1].offset = offset;
511 align = MONO_ARCH_FRAME_ALIGNMENT;
512 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
513 arg_info [k].pad = pad;
520 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
522 /* FIXME: handle returning a struct */
524 if (sig && MONO_TYPE_ISSTRUCT (sig->ret))
525 return (gpointer)regs [mips_a1];
526 return (gpointer)regs [mips_a0];
530 * Initialize the cpu to execute managed code.
533 mono_arch_cpu_init (void)
538 * Initialize architecture specific code.
541 mono_arch_init (void)
543 InitializeCriticalSection (&mini_arch_mutex);
547 * Cleanup architecture specific code.
550 mono_arch_cleanup (void)
552 DeleteCriticalSection (&mini_arch_mutex);
556 * This function returns the optimizations supported on this cpu.
559 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
563 /* no mips-specific optimizations yet */
569 is_regsize_var (MonoType *t) {
572 t = mono_type_get_underlying_type (t);
576 #if (SIZEOF_REGISTER == 8)
583 case MONO_TYPE_FNPTR:
585 case MONO_TYPE_OBJECT:
586 case MONO_TYPE_STRING:
587 case MONO_TYPE_CLASS:
588 case MONO_TYPE_SZARRAY:
589 case MONO_TYPE_ARRAY:
591 case MONO_TYPE_GENERICINST:
592 if (!mono_type_generic_inst_is_valuetype (t))
595 case MONO_TYPE_VALUETYPE:
602 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
607 for (i = 0; i < cfg->num_varinfo; i++) {
608 MonoInst *ins = cfg->varinfo [i];
609 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
612 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
615 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
618 /* we can only allocate 32 bit values */
619 if (is_regsize_var (ins->inst_vtype)) {
620 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
621 g_assert (i == vmv->idx);
622 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
630 mono_arch_get_global_int_regs (MonoCompile *cfg)
634 regs = g_list_prepend (regs, (gpointer)mips_s0);
635 regs = g_list_prepend (regs, (gpointer)mips_s1);
636 regs = g_list_prepend (regs, (gpointer)mips_s2);
637 regs = g_list_prepend (regs, (gpointer)mips_s3);
638 regs = g_list_prepend (regs, (gpointer)mips_s4);
639 //regs = g_list_prepend (regs, (gpointer)mips_s5);
640 regs = g_list_prepend (regs, (gpointer)mips_s6);
641 regs = g_list_prepend (regs, (gpointer)mips_s7);
647 * mono_arch_regalloc_cost:
649 * Return the cost, in number of memory references, of the action of
650 * allocating the variable VMV into a register during global register
654 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
661 args_onto_stack (CallInfo *info)
663 g_assert (!info->on_stack);
664 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
665 info->on_stack = TRUE;
666 info->stack_size = MIPS_STACK_PARAM_OFFSET;
669 #if _MIPS_SIM == _ABIO32
671 * O32 calling convention version
675 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
676 /* First, see if we need to drop onto the stack */
677 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
678 args_onto_stack (info);
680 /* Now, place the argument */
681 if (info->on_stack) {
682 ainfo->regtype = RegTypeBase;
683 ainfo->reg = mips_sp; /* in the caller */
684 ainfo->offset = info->stack_size;
687 ainfo->regtype = RegTypeGeneral;
688 ainfo->reg = info->gr;
690 info->gr_passed = TRUE;
692 info->stack_size += 4;
696 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
697 /* First, see if we need to drop onto the stack */
698 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
699 args_onto_stack (info);
701 /* Now, place the argument */
702 if (info->on_stack) {
703 g_assert (info->stack_size % 4 == 0);
704 info->stack_size += (info->stack_size % 8);
706 ainfo->regtype = RegTypeBase;
707 ainfo->reg = mips_sp; /* in the caller */
708 ainfo->offset = info->stack_size;
711 // info->gr must be a0 or a2
712 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
713 g_assert(info->gr <= MIPS_LAST_ARG_REG);
715 ainfo->regtype = RegTypeGeneral;
716 ainfo->reg = info->gr;
718 info->gr_passed = TRUE;
720 info->stack_size += 8;
724 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
725 /* First, see if we need to drop onto the stack */
726 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
727 args_onto_stack (info);
729 /* Now, place the argument */
730 if (info->on_stack) {
731 ainfo->regtype = RegTypeBase;
732 ainfo->reg = mips_sp; /* in the caller */
733 ainfo->offset = info->stack_size;
736 /* Only use FP regs for args if no int args passed yet */
737 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
738 ainfo->regtype = RegTypeFP;
739 ainfo->reg = info->fr;
740 /* Even though it's a single-precision float, it takes up two FP regs */
742 /* FP and GP slots do not overlap */
746 /* Passing single-precision float arg in a GP register
747 * such as: func (0, 1.0, 2, 3);
748 * In this case, only one 'gr' register is consumed.
750 ainfo->regtype = RegTypeGeneral;
751 ainfo->reg = info->gr;
754 info->gr_passed = TRUE;
757 info->stack_size += 4;
761 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
762 /* First, see if we need to drop onto the stack */
763 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
764 args_onto_stack (info);
766 /* Now, place the argument */
767 if (info->on_stack) {
768 g_assert(info->stack_size % 4 == 0);
769 info->stack_size += (info->stack_size % 8);
771 ainfo->regtype = RegTypeBase;
772 ainfo->reg = mips_sp; /* in the caller */
773 ainfo->offset = info->stack_size;
776 /* Only use FP regs for args if no int args passed yet */
777 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
778 ainfo->regtype = RegTypeFP;
779 ainfo->reg = info->fr;
781 /* FP and GP slots do not overlap */
785 // info->gr must be a0 or a2
786 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
787 g_assert(info->gr <= MIPS_LAST_ARG_REG);
789 ainfo->regtype = RegTypeGeneral;
790 ainfo->reg = info->gr;
792 info->gr_passed = TRUE;
795 info->stack_size += 8;
797 #elif _MIPS_SIM == _ABIN32
799 * N32 calling convention version
803 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
804 /* First, see if we need to drop onto the stack */
805 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
806 args_onto_stack (info);
808 /* Now, place the argument */
809 if (info->on_stack) {
810 ainfo->regtype = RegTypeBase;
811 ainfo->reg = mips_sp; /* in the caller */
812 ainfo->offset = info->stack_size;
813 info->stack_size += SIZEOF_REGISTER;
816 ainfo->regtype = RegTypeGeneral;
817 ainfo->reg = info->gr;
819 info->gr_passed = TRUE;
824 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
825 /* First, see if we need to drop onto the stack */
826 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
827 args_onto_stack (info);
829 /* Now, place the argument */
830 if (info->on_stack) {
831 g_assert (info->stack_size % 4 == 0);
832 info->stack_size += (info->stack_size % 8);
834 ainfo->regtype = RegTypeBase;
835 ainfo->reg = mips_sp; /* in the caller */
836 ainfo->offset = info->stack_size;
837 info->stack_size += SIZEOF_REGISTER;
840 g_assert (info->gr <= MIPS_LAST_ARG_REG);
842 ainfo->regtype = RegTypeGeneral;
843 ainfo->reg = info->gr;
845 info->gr_passed = TRUE;
850 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
851 /* First, see if we need to drop onto the stack */
852 if (!info->on_stack) {
853 if (info->gr > MIPS_LAST_ARG_REG)
854 args_onto_stack (info);
855 else if (info->fr > MIPS_LAST_FPARG_REG)
856 args_onto_stack (info);
859 /* Now, place the argument */
860 if (info->on_stack) {
861 ainfo->regtype = RegTypeBase;
862 ainfo->reg = mips_sp; /* in the caller */
863 ainfo->offset = info->stack_size;
864 info->stack_size += FREG_SIZE;
867 ainfo->regtype = RegTypeFP;
868 ainfo->reg = info->fr;
870 /* FP and GP slots do not overlap */
876 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
877 /* First, see if we need to drop onto the stack */
878 if (!info->on_stack) {
879 if (info->gr > MIPS_LAST_ARG_REG)
880 args_onto_stack (info);
881 else if (info->fr > MIPS_LAST_FPARG_REG)
882 args_onto_stack (info);
885 /* Now, place the argument */
886 if (info->on_stack) {
887 g_assert(info->stack_size % 4 == 0);
888 info->stack_size += (info->stack_size % 8);
890 ainfo->regtype = RegTypeBase;
891 ainfo->reg = mips_sp; /* in the caller */
892 ainfo->offset = info->stack_size;
893 info->stack_size += FREG_SIZE;
896 ainfo->regtype = RegTypeFP;
897 ainfo->reg = info->fr;
899 /* FP and GP slots do not overlap */
906 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
909 int n = sig->hasthis + sig->param_count;
911 MonoType* simpletype;
912 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
914 cinfo->fr = MIPS_FIRST_FPARG_REG;
915 cinfo->gr = MIPS_FIRST_ARG_REG;
916 cinfo->stack_size = 0;
918 DEBUG(printf("calculate_sizes\n"));
920 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
924 /* handle returning a struct */
925 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
926 cinfo->struct_ret = cinfo->gr;
927 add_int32_arg (cinfo, &cinfo->ret);
931 add_int32_arg (cinfo, cinfo->args + n);
936 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
937 * the first argument, allowing 'this' to be always passed in the first arg reg.
938 * Also do this if the first argument is a reference type, since virtual calls
939 * are sometimes made using calli without sig->hasthis set, like in the delegate
942 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]))))) {
944 add_int32_arg (cinfo, cinfo->args + n);
947 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
951 add_int32_arg (cinfo, &cinfo->ret);
952 cinfo->struct_ret = cinfo->ret.reg;
956 add_int32_arg (cinfo, cinfo->args + n);
960 if (cinfo->vtype_retaddr) {
961 add_int32_arg (cinfo, &cinfo->ret);
962 cinfo->struct_ret = cinfo->ret.reg;
967 DEBUG(printf("params: %d\n", sig->param_count));
968 for (i = pstart; i < sig->param_count; ++i) {
969 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
970 /* Prevent implicit arguments and sig_cookie from
971 being passed in registers */
972 args_onto_stack (cinfo);
973 /* Emit the signature cookie just before the implicit arguments */
974 add_int32_arg (cinfo, &cinfo->sig_cookie);
976 DEBUG(printf("param %d: ", i));
977 if (sig->params [i]->byref) {
978 DEBUG(printf("byref\n"));
979 add_int32_arg (cinfo, &cinfo->args[n]);
983 simpletype = mono_type_get_underlying_type (sig->params [i]);
984 switch (simpletype->type) {
985 case MONO_TYPE_BOOLEAN:
988 DEBUG(printf("1 byte\n"));
989 cinfo->args [n].size = 1;
990 add_int32_arg (cinfo, &cinfo->args[n]);
996 DEBUG(printf("2 bytes\n"));
997 cinfo->args [n].size = 2;
998 add_int32_arg (cinfo, &cinfo->args[n]);
1003 DEBUG(printf("4 bytes\n"));
1004 cinfo->args [n].size = 4;
1005 add_int32_arg (cinfo, &cinfo->args[n]);
1011 case MONO_TYPE_FNPTR:
1012 case MONO_TYPE_CLASS:
1013 case MONO_TYPE_OBJECT:
1014 case MONO_TYPE_STRING:
1015 case MONO_TYPE_SZARRAY:
1016 case MONO_TYPE_ARRAY:
1017 cinfo->args [n].size = sizeof (gpointer);
1018 add_int32_arg (cinfo, &cinfo->args[n]);
1021 case MONO_TYPE_GENERICINST:
1022 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1023 cinfo->args [n].size = sizeof (gpointer);
1024 add_int32_arg (cinfo, &cinfo->args[n]);
1029 case MONO_TYPE_VALUETYPE: {
1032 int has_offset = FALSE;
1034 gint size, alignment;
1037 klass = mono_class_from_mono_type (sig->params [i]);
1039 size = mono_class_native_size (klass, NULL);
1041 size = mono_class_value_size (klass, NULL);
1042 alignment = mono_class_min_align (klass);
1043 #if MIPS_PASS_STRUCTS_BY_VALUE
1044 /* Need to do alignment if struct contains long or double */
1045 if (alignment > 4) {
1046 if (cinfo->stack_size & (alignment - 1)) {
1047 add_int32_arg (cinfo, &dummy_arg);
1049 g_assert (!(cinfo->stack_size & (alignment - 1)));
1053 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1054 mono_class_native_size (sig->params [i]->data.klass, NULL),
1055 cinfo->stack_size, alignment);
1057 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1058 g_assert (cinfo->args [n].size == 0);
1059 g_assert (cinfo->args [n].vtsize == 0);
1060 for (j = 0; j < nwords; ++j) {
1062 add_int32_arg (cinfo, &cinfo->args [n]);
1063 if (cinfo->on_stack)
1066 add_int32_arg (cinfo, &dummy_arg);
1067 if (!has_offset && cinfo->on_stack) {
1068 cinfo->args [n].offset = dummy_arg.offset;
1072 if (cinfo->on_stack)
1073 cinfo->args [n].vtsize += 1;
1075 cinfo->args [n].size += 1;
1077 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1078 cinfo->args [n].regtype = RegTypeStructByVal;
1080 add_int32_arg (cinfo, &cinfo->args[n]);
1081 cinfo->args [n].regtype = RegTypeStructByAddr;
1086 case MONO_TYPE_TYPEDBYREF: {
1087 /* keep in sync or merge with the valuetype case */
1088 #if MIPS_PASS_STRUCTS_BY_VALUE
1090 int size = sizeof (MonoTypedRef);
1091 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1092 cinfo->args [n].regtype = RegTypeStructByVal;
1093 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
1094 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
1095 int n_in_regs = rest >= nwords? nwords: rest;
1096 cinfo->args [n].size = n_in_regs;
1097 cinfo->args [n].vtsize = nwords - n_in_regs;
1098 cinfo->args [n].reg = cinfo->gr;
1099 cinfo->gr += n_in_regs;
1100 cinfo->gr_passed = TRUE;
1102 cinfo->args [n].size = 0;
1103 cinfo->args [n].vtsize = nwords;
1105 if (cinfo->args [n].vtsize > 0) {
1106 if (!cinfo->on_stack)
1107 args_onto_stack (cinfo);
1108 g_assert(cinfo->on_stack);
1109 cinfo->args [n].offset = cinfo->stack_size;
1110 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
1111 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
1115 add_int32_arg (cinfo, &cinfo->args[n]);
1116 cinfo->args [n].regtype = RegTypeStructByAddr;
1123 DEBUG(printf("8 bytes\n"));
1124 cinfo->args [n].size = 8;
1125 add_int64_arg (cinfo, &cinfo->args[n]);
1129 DEBUG(printf("R4\n"));
1130 cinfo->args [n].size = 4;
1131 add_float32_arg (cinfo, &cinfo->args[n]);
1135 DEBUG(printf("R8\n"));
1136 cinfo->args [n].size = 8;
1137 add_float64_arg (cinfo, &cinfo->args[n]);
1141 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1146 simpletype = mono_type_get_underlying_type (sig->ret);
1147 switch (simpletype->type) {
1148 case MONO_TYPE_BOOLEAN:
1153 case MONO_TYPE_CHAR:
1159 case MONO_TYPE_FNPTR:
1160 case MONO_TYPE_CLASS:
1161 case MONO_TYPE_OBJECT:
1162 case MONO_TYPE_SZARRAY:
1163 case MONO_TYPE_ARRAY:
1164 case MONO_TYPE_STRING:
1165 cinfo->ret.reg = mips_v0;
1169 cinfo->ret.reg = mips_v0;
1173 cinfo->ret.reg = mips_f0;
1174 cinfo->ret.regtype = RegTypeFP;
1176 case MONO_TYPE_GENERICINST:
1177 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1178 cinfo->ret.reg = mips_v0;
1182 case MONO_TYPE_VALUETYPE:
1184 case MONO_TYPE_TYPEDBYREF:
1185 case MONO_TYPE_VOID:
1188 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1192 /* align stack size to 16 */
1193 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1195 cinfo->stack_usage = cinfo->stack_size;
1201 * Set var information according to the calling convention. mips version.
1202 * The locals var stuff should most likely be split in another method.
1205 mono_arch_allocate_vars (MonoCompile *cfg)
1207 MonoMethodSignature *sig;
1208 MonoMethodHeader *header;
1210 int i, offset, size, align, curinst;
1211 int frame_reg = mips_sp;
1212 guint32 iregs_to_save = 0;
1214 guint32 fregs_to_restore;
1217 /* spill down, we'll fix it in a separate pass */
1218 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1220 /* allow room for the vararg method args: void* and long/double */
1221 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1222 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1224 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1225 * call convs needs to be handled this way.
1227 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1228 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1230 /* gtk-sharp and other broken code will dllimport vararg functions even with
1231 * non-varargs signatures. Since there is little hope people will get this right
1232 * we assume they won't.
1234 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1235 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1237 /* a0-a3 always present */
1238 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1240 header = cfg->header;
1242 sig = mono_method_signature (cfg->method);
1245 * We use the frame register also for any method that has
1246 * exception clauses. This way, when the handlers are called,
1247 * the code will reference local variables using the frame reg instead of
1248 * the stack pointer: if we had to restore the stack pointer, we'd
1249 * corrupt the method frames that are already on the stack (since
1250 * filters get called before stack unwinding happens) when the filter
1251 * code would call any method (this also applies to finally etc.).
1254 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
1255 frame_reg = mips_fp;
1256 cfg->frame_reg = frame_reg;
1257 if (frame_reg != mips_sp) {
1258 cfg->used_int_regs |= 1 << frame_reg;
1263 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1264 /* FIXME: handle long and FP values */
1265 switch (mono_type_get_underlying_type (sig->ret)->type) {
1266 case MONO_TYPE_VOID:
1270 cfg->ret->opcode = OP_REGVAR;
1271 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1274 cfg->ret->opcode = OP_REGVAR;
1275 cfg->ret->inst_c0 = mips_v0;
1279 /* Space for outgoing parameters, including a0-a3 */
1280 offset += cfg->param_area;
1282 /* allow room to save the return value (if it's a struct) */
1283 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1286 if (sig->call_convention == MONO_CALL_VARARG) {
1287 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1290 /* Now handle the local variables */
1292 curinst = cfg->locals_start;
1293 for (i = curinst; i < cfg->num_varinfo; ++i) {
1294 inst = cfg->varinfo [i];
1295 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1298 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1299 * pinvoke wrappers when they call functions returning structure
1301 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1302 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1304 size = mono_type_size (inst->inst_vtype, &align);
1306 offset += align - 1;
1307 offset &= ~(align - 1);
1308 inst->inst_offset = offset;
1309 inst->opcode = OP_REGOFFSET;
1310 inst->inst_basereg = frame_reg;
1312 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1315 /* Space for LMF (if needed) */
1317 if (cfg->method->save_lmf) {
1318 /* align the offset to 16 bytes */
1319 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1320 cfg->arch.lmf_offset = offset;
1321 offset += sizeof (MonoLMF);
1325 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1326 * args or return vals. Extra stack space avoids this in a lot of cases.
1328 offset += EXTRA_STACK_SPACE;
1330 /* Space for saved registers */
1331 cfg->arch.iregs_offset = offset;
1333 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1335 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1337 if (iregs_to_save) {
1338 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1339 if (iregs_to_save & (1 << i)) {
1340 offset += SIZEOF_REGISTER;
1345 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1346 * args or return vals. Extra stack space avoids this in a lot of cases.
1348 offset += EXTRA_STACK_SPACE;
1350 /* saved float registers */
1352 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1353 if (fregs_to_restore) {
1354 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1355 if (fregs_to_restore & (1 << i)) {
1356 offset += sizeof(double);
1362 #if _MIPS_SIM == _ABIO32
1363 /* Now add space for saving the ra */
1364 offset += SIZEOF_VOID_P;
1367 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1368 cfg->stack_offset = offset;
1369 cfg->arch.local_alloc_offset = cfg->stack_offset;
1373 * Now allocate stack slots for the int arg regs (a0 - a3)
1374 * On MIPS o32, these are just above the incoming stack pointer
1375 * Even if the arg has been assigned to a regvar, it gets a stack slot
1378 /* Return struct-by-value results in a hidden first argument */
1379 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1380 cfg->vret_addr->opcode = OP_REGOFFSET;
1381 cfg->vret_addr->inst_c0 = mips_a0;
1382 cfg->vret_addr->inst_offset = offset;
1383 cfg->vret_addr->inst_basereg = frame_reg;
1384 offset += SIZEOF_REGISTER;
1387 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1388 inst = cfg->args [i];
1389 if (inst->opcode != OP_REGVAR) {
1392 if (sig->hasthis && (i == 0))
1393 arg_type = &mono_defaults.object_class->byval_arg;
1395 arg_type = sig->params [i - sig->hasthis];
1397 inst->opcode = OP_REGOFFSET;
1398 size = mono_type_size (arg_type, &align);
1400 if (size < SIZEOF_REGISTER) {
1401 size = SIZEOF_REGISTER;
1402 align = SIZEOF_REGISTER;
1404 inst->inst_basereg = frame_reg;
1405 offset = (offset + align - 1) & ~(align - 1);
1406 inst->inst_offset = offset;
1408 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1409 cfg->sig_cookie += size;
1410 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1413 #if _MIPS_SIM == _ABIO32
1414 /* o32: Even a0-a3 get stack slots */
1415 size = SIZEOF_REGISTER;
1416 align = SIZEOF_REGISTER;
1417 inst->inst_basereg = frame_reg;
1418 offset = (offset + align - 1) & ~(align - 1);
1419 inst->inst_offset = offset;
1421 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1422 cfg->sig_cookie += size;
1423 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1427 #if _MIPS_SIM == _ABIN32
1428 /* Now add space for saving the ra */
1429 offset += SIZEOF_VOID_P;
1432 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1433 cfg->stack_offset = offset;
1434 cfg->arch.local_alloc_offset = cfg->stack_offset;
1439 mono_arch_create_vars (MonoCompile *cfg)
1441 MonoMethodSignature *sig;
1443 sig = mono_method_signature (cfg->method);
1445 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1446 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1447 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1448 printf ("vret_addr = ");
1449 mono_print_ins (cfg->vret_addr);
1454 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1455 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1459 * take the arguments and generate the arch-specific
1460 * instructions to properly call the function in call.
1461 * This includes pushing, moving arguments to the right register
1463 * Issue: who does the spilling if needed, and when?
1466 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1468 int sig_reg = mono_alloc_ireg (cfg);
1470 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1471 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1472 mips_sp, cinfo->sig_cookie.offset, sig_reg);
1476 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1479 MonoMethodSignature *sig;
1484 sig = call->signature;
1485 n = sig->param_count + sig->hasthis;
1487 cinfo = calculate_sizes (sig, sig->pinvoke);
1488 if (cinfo->struct_ret)
1489 call->used_iregs |= 1 << cinfo->struct_ret;
1491 for (i = 0; i < n; ++i) {
1492 ArgInfo *ainfo = cinfo->args + i;
1495 if (i >= sig->hasthis)
1496 t = sig->params [i - sig->hasthis];
1498 t = &mono_defaults.int_class->byval_arg;
1499 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1501 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1502 emit_sig_cookie (cfg, call, cinfo);
1503 if (is_virtual && i == 0) {
1504 /* the argument will be attached to the call instrucion */
1505 in = call->args [i];
1506 call->used_iregs |= 1 << ainfo->reg;
1509 in = call->args [i];
1510 if (ainfo->regtype == RegTypeGeneral) {
1511 #if SIZEOF_REGISTER == 4
1512 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1513 MONO_INST_NEW (cfg, ins, OP_MOVE);
1514 ins->dreg = mono_alloc_ireg (cfg);
1515 ins->sreg1 = in->dreg + 1;
1516 MONO_ADD_INS (cfg->cbb, ins);
1517 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1519 MONO_INST_NEW (cfg, ins, OP_MOVE);
1520 ins->dreg = mono_alloc_ireg (cfg);
1521 ins->sreg1 = in->dreg + 2;
1522 MONO_ADD_INS (cfg->cbb, ins);
1523 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1526 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1529 #if PROMOTE_R4_TO_R8
1530 /* ??? - convert to single first? */
1531 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1532 ins->dreg = mono_alloc_freg (cfg);
1533 ins->sreg1 = in->dreg;
1534 MONO_ADD_INS (cfg->cbb, ins);
1539 /* trying to load float value into int registers */
1540 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1541 ins->dreg = mono_alloc_ireg (cfg);
1543 MONO_ADD_INS (cfg->cbb, ins);
1544 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1545 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1546 /* trying to load float value into int registers */
1547 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1548 ins->dreg = mono_alloc_ireg (cfg);
1549 ins->sreg1 = in->dreg;
1550 MONO_ADD_INS (cfg->cbb, ins);
1551 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1553 MONO_INST_NEW (cfg, ins, OP_MOVE);
1554 ins->dreg = mono_alloc_ireg (cfg);
1555 ins->sreg1 = in->dreg;
1556 MONO_ADD_INS (cfg->cbb, ins);
1557 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1559 } else if (ainfo->regtype == RegTypeStructByAddr) {
1560 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1561 ins->opcode = OP_OUTARG_VT;
1562 ins->sreg1 = in->dreg;
1563 ins->klass = in->klass;
1564 ins->inst_p0 = call;
1565 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1566 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1567 MONO_ADD_INS (cfg->cbb, ins);
1568 } else if (ainfo->regtype == RegTypeStructByVal) {
1569 /* this is further handled in mono_arch_emit_outarg_vt () */
1570 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1571 ins->opcode = OP_OUTARG_VT;
1572 ins->sreg1 = in->dreg;
1573 ins->klass = in->klass;
1574 ins->inst_p0 = call;
1575 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1576 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1577 MONO_ADD_INS (cfg->cbb, ins);
1578 } else if (ainfo->regtype == RegTypeBase) {
1579 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1580 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1581 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1582 if (t->type == MONO_TYPE_R8)
1583 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1585 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1587 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1589 } else if (ainfo->regtype == RegTypeFP) {
1590 if (t->type == MONO_TYPE_VALUETYPE) {
1591 /* this is further handled in mono_arch_emit_outarg_vt () */
1592 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1593 ins->opcode = OP_OUTARG_VT;
1594 ins->sreg1 = in->dreg;
1595 ins->klass = in->klass;
1596 ins->inst_p0 = call;
1597 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1598 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1599 MONO_ADD_INS (cfg->cbb, ins);
1601 cfg->flags |= MONO_CFG_HAS_FPOUT;
1603 int dreg = mono_alloc_freg (cfg);
1605 if (ainfo->size == 4) {
1606 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1608 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1610 ins->sreg1 = in->dreg;
1611 MONO_ADD_INS (cfg->cbb, ins);
1614 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1615 cfg->flags |= MONO_CFG_HAS_FPOUT;
1618 g_assert_not_reached ();
1622 /* Emit the signature cookie in the case that there is no
1623 additional argument */
1624 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1625 emit_sig_cookie (cfg, call, cinfo);
1627 if (cinfo->struct_ret) {
1630 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1631 vtarg->sreg1 = call->vret_var->dreg;
1632 vtarg->dreg = mono_alloc_preg (cfg);
1633 MONO_ADD_INS (cfg->cbb, vtarg);
1635 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1639 * Reverse the call->out_args list.
1642 MonoInst *prev = NULL, *list = call->out_args, *next;
1649 call->out_args = prev;
1652 call->stack_usage = cinfo->stack_usage;
1653 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1654 #if _MIPS_SIM == _ABIO32
1655 /* a0-a3 always present */
1656 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1658 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1659 cfg->flags |= MONO_CFG_HAS_CALLS;
1661 * should set more info in call, such as the stack space
1662 * used by the args that needs to be added back to esp
1669 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1671 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1672 ArgInfo *ainfo = ins->inst_p1;
1673 int ovf_size = ainfo->vtsize;
1674 int doffset = ainfo->offset;
1675 int i, soffset, dreg;
1677 if (ainfo->regtype == RegTypeStructByVal) {
1679 if (cfg->verbose_level > 0) {
1680 char* nm = mono_method_full_name (cfg->method, TRUE);
1681 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1682 nm, doffset, ainfo->size, ovf_size);
1688 for (i = 0; i < ainfo->size; ++i) {
1689 dreg = mono_alloc_ireg (cfg);
1690 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1691 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1692 soffset += SIZEOF_REGISTER;
1694 if (ovf_size != 0) {
1695 mini_emit_memcpy (cfg, mips_fp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1697 } else if (ainfo->regtype == RegTypeFP) {
1698 int tmpr = mono_alloc_freg (cfg);
1700 if (ainfo->size == 4)
1701 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1703 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1704 dreg = mono_alloc_freg (cfg);
1705 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1706 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1708 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1712 /* FIXME: alignment? */
1713 if (call->signature->pinvoke) {
1714 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1715 vtcopy->backend.is_pinvoke = 1;
1717 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1720 g_assert (ovf_size > 0);
1722 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1723 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1726 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1728 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1733 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1735 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1736 mono_method_signature (method)->ret);
1739 #if (SIZEOF_REGISTER == 4)
1740 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1743 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1744 ins->sreg1 = val->dreg + 1;
1745 ins->sreg2 = val->dreg + 2;
1746 MONO_ADD_INS (cfg->cbb, ins);
1750 if (ret->type == MONO_TYPE_R8) {
1751 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1754 if (ret->type == MONO_TYPE_R4) {
1755 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1759 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1763 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1765 MonoInst *ins, *n, *last_ins = NULL;
1767 if (cfg->verbose_level > 2)
1768 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1771 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1772 if (cfg->verbose_level > 2)
1773 mono_print_ins_index (0, ins);
1775 switch (ins->opcode) {
1777 case OP_LOAD_MEMBASE:
1778 case OP_LOADI4_MEMBASE:
1780 * OP_IADD reg2, reg1, const1
1781 * OP_LOAD_MEMBASE const2(reg2), reg3
1783 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1785 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)){
1786 int const1 = last_ins->inst_imm;
1787 int const2 = ins->inst_offset;
1789 if (mips_is_imm16 (const1 + const2)) {
1790 ins->inst_basereg = last_ins->sreg1;
1791 ins->inst_offset = const1 + const2;
1801 bb->last_ins = last_ins;
1805 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1807 MonoInst *ins, *n, *last_ins = NULL;
1810 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1811 MonoInst *last_ins = ins->prev;
1813 switch (ins->opcode) {
1815 /* remove unnecessary multiplication with 1 */
1816 if (ins->inst_imm == 1) {
1817 if (ins->dreg != ins->sreg1) {
1818 ins->opcode = OP_MOVE;
1820 MONO_DELETE_INS (bb, ins);
1824 int power2 = mono_is_power_of_two (ins->inst_imm);
1826 ins->opcode = OP_SHL_IMM;
1827 ins->inst_imm = power2;
1831 case OP_LOAD_MEMBASE:
1832 case OP_LOADI4_MEMBASE:
1834 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1835 * OP_LOAD_MEMBASE offset(basereg), reg
1837 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1838 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1839 ins->inst_basereg == last_ins->inst_destbasereg &&
1840 ins->inst_offset == last_ins->inst_offset) {
1841 if (ins->dreg == last_ins->sreg1) {
1842 MONO_DELETE_INS (bb, ins);
1845 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1846 ins->opcode = OP_MOVE;
1847 ins->sreg1 = last_ins->sreg1;
1852 * Note: reg1 must be different from the basereg in the second load
1853 * OP_LOAD_MEMBASE offset(basereg), reg1
1854 * OP_LOAD_MEMBASE offset(basereg), reg2
1856 * OP_LOAD_MEMBASE offset(basereg), reg1
1857 * OP_MOVE reg1, reg2
1859 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1860 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1861 ins->inst_basereg != last_ins->dreg &&
1862 ins->inst_basereg == last_ins->inst_basereg &&
1863 ins->inst_offset == last_ins->inst_offset) {
1865 if (ins->dreg == last_ins->dreg) {
1866 MONO_DELETE_INS (bb, ins);
1869 ins->opcode = OP_MOVE;
1870 ins->sreg1 = last_ins->dreg;
1873 //g_assert_not_reached ();
1878 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1879 * OP_LOAD_MEMBASE offset(basereg), reg
1881 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1882 * OP_ICONST reg, imm
1884 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1885 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1886 ins->inst_basereg == last_ins->inst_destbasereg &&
1887 ins->inst_offset == last_ins->inst_offset) {
1888 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1889 ins->opcode = OP_ICONST;
1890 ins->inst_c0 = last_ins->inst_imm;
1891 g_assert_not_reached (); // check this rule
1896 case OP_LOADU1_MEMBASE:
1897 case OP_LOADI1_MEMBASE:
1898 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1899 ins->inst_basereg == last_ins->inst_destbasereg &&
1900 ins->inst_offset == last_ins->inst_offset) {
1901 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1902 ins->sreg1 = last_ins->sreg1;
1905 case OP_LOADU2_MEMBASE:
1906 case OP_LOADI2_MEMBASE:
1907 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1908 ins->inst_basereg == last_ins->inst_destbasereg &&
1909 ins->inst_offset == last_ins->inst_offset) {
1910 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1911 ins->sreg1 = last_ins->sreg1;
1914 case OP_ICONV_TO_I4:
1915 case OP_ICONV_TO_U4:
1917 ins->opcode = OP_MOVE;
1921 if (ins->dreg == ins->sreg1) {
1922 MONO_DELETE_INS (bb, ins);
1926 * OP_MOVE sreg, dreg
1927 * OP_MOVE dreg, sreg
1929 if (last_ins && last_ins->opcode == OP_MOVE &&
1930 ins->sreg1 == last_ins->dreg &&
1931 ins->dreg == last_ins->sreg1) {
1932 MONO_DELETE_INS (bb, ins);
1940 bb->last_ins = last_ins;
1944 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
1952 switch (ins->opcode) {
1955 case OP_LCOMPARE_IMM:
1956 mono_print_ins (ins);
1957 g_assert_not_reached ();
1960 tmp1 = mono_alloc_ireg (cfg);
1961 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1962 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1963 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1964 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1969 tmp1 = mono_alloc_ireg (cfg);
1970 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1971 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1972 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1973 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1978 tmp1 = mono_alloc_ireg (cfg);
1979 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1980 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1981 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1982 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1987 tmp1 = mono_alloc_ireg (cfg);
1988 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1989 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1990 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1991 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2003 mono_print_ins (ins);
2004 g_assert_not_reached ();
2007 tmp1 = mono_alloc_ireg (cfg);
2008 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2009 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2010 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2011 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2019 case OP_LCONV_TO_I1:
2020 case OP_LCONV_TO_I2:
2021 case OP_LCONV_TO_I4:
2022 case OP_LCONV_TO_I8:
2023 case OP_LCONV_TO_R4:
2024 case OP_LCONV_TO_R8:
2025 case OP_LCONV_TO_U4:
2026 case OP_LCONV_TO_U8:
2027 case OP_LCONV_TO_U2:
2028 case OP_LCONV_TO_U1:
2030 case OP_LCONV_TO_OVF_I:
2031 case OP_LCONV_TO_OVF_U:
2033 mono_print_ins (ins);
2034 g_assert_not_reached ();
2037 tmp1 = mono_alloc_ireg (cfg);
2038 tmp2 = mono_alloc_ireg (cfg);
2039 tmp3 = mono_alloc_ireg (cfg);
2040 tmp4 = mono_alloc_ireg (cfg);
2041 tmp5 = mono_alloc_ireg (cfg);
2043 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2045 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2046 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2048 /* add the high 32-bits, and add in the carry from the low 32-bits */
2049 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2050 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2052 /* Overflow happens if
2053 * neg + neg = pos or
2055 * XOR of the high bits returns 0 if the signs match
2056 * XOR of that with the high bit of the result return 1 if overflow.
2059 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2060 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2062 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2063 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2064 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2066 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2067 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2068 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2070 /* Now, if (tmp4 == 0) then overflow */
2071 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2075 case OP_LADD_OVF_UN:
2076 tmp1 = mono_alloc_ireg (cfg);
2077 tmp2 = mono_alloc_ireg (cfg);
2079 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2080 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2081 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2082 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2083 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2084 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2089 case OP_LMUL_OVF_UN:
2090 mono_print_ins (ins);
2091 g_assert_not_reached ();
2094 tmp1 = mono_alloc_ireg (cfg);
2095 tmp2 = mono_alloc_ireg (cfg);
2096 tmp3 = mono_alloc_ireg (cfg);
2097 tmp4 = mono_alloc_ireg (cfg);
2098 tmp5 = mono_alloc_ireg (cfg);
2100 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2102 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2103 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2104 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2106 /* Overflow happens if
2107 * neg - pos = pos or
2109 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2111 * tmp1 = (lhs ^ rhs)
2112 * tmp2 = (lhs ^ result)
2113 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2116 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2117 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2118 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2119 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2121 /* Now, if (tmp4 == 1) then overflow */
2122 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2126 case OP_LSUB_OVF_UN:
2127 tmp1 = mono_alloc_ireg (cfg);
2128 tmp2 = mono_alloc_ireg (cfg);
2130 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2131 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2132 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2133 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2135 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2136 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2140 case OP_LCONV_TO_OVF_I1_UN:
2141 case OP_LCONV_TO_OVF_I2_UN:
2142 case OP_LCONV_TO_OVF_I4_UN:
2143 case OP_LCONV_TO_OVF_I8_UN:
2144 case OP_LCONV_TO_OVF_U1_UN:
2145 case OP_LCONV_TO_OVF_U2_UN:
2146 case OP_LCONV_TO_OVF_U4_UN:
2147 case OP_LCONV_TO_OVF_U8_UN:
2148 case OP_LCONV_TO_OVF_I_UN:
2149 case OP_LCONV_TO_OVF_U_UN:
2150 case OP_LCONV_TO_OVF_I1:
2151 case OP_LCONV_TO_OVF_U1:
2152 case OP_LCONV_TO_OVF_I2:
2153 case OP_LCONV_TO_OVF_U2:
2154 case OP_LCONV_TO_OVF_I4:
2155 case OP_LCONV_TO_OVF_U4:
2156 case OP_LCONV_TO_OVF_I8:
2157 case OP_LCONV_TO_OVF_U8:
2165 case OP_LCONV_TO_R_UN:
2171 case OP_LSHR_UN_IMM:
2173 case OP_LDIV_UN_IMM:
2175 case OP_LREM_UN_IMM:
2186 mono_print_ins (ins);
2187 g_assert_not_reached ();
2189 case OP_LCONV_TO_R8_2:
2190 case OP_LCONV_TO_R4_2:
2191 case OP_LCONV_TO_R_UN_2:
2193 case OP_LCONV_TO_OVF_I4_2:
2194 tmp1 = mono_alloc_ireg (cfg);
2196 /* Overflows if reg2 != sign extension of reg1 */
2197 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2198 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2199 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2207 mono_print_ins (ins);
2208 g_assert_not_reached ();
2216 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2224 switch (ins->opcode) {
2226 tmp1 = mono_alloc_ireg (cfg);
2227 tmp2 = mono_alloc_ireg (cfg);
2228 tmp3 = mono_alloc_ireg (cfg);
2229 tmp4 = mono_alloc_ireg (cfg);
2230 tmp5 = mono_alloc_ireg (cfg);
2232 /* add the operands */
2234 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2236 /* Overflow happens if
2237 * neg + neg = pos or
2240 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2241 * XOR of the high bit returns 0 if the signs match
2242 * XOR of that with the high bit of the result return 1 if overflow.
2245 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2246 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2248 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2249 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2250 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2252 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2253 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2255 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2257 /* Now, if (tmp5 == 0) then overflow */
2258 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2259 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2260 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2264 case OP_IADD_OVF_UN:
2265 tmp1 = mono_alloc_ireg (cfg);
2267 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2268 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2269 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2270 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2271 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2276 tmp1 = mono_alloc_ireg (cfg);
2277 tmp2 = mono_alloc_ireg (cfg);
2278 tmp3 = mono_alloc_ireg (cfg);
2279 tmp4 = mono_alloc_ireg (cfg);
2280 tmp5 = mono_alloc_ireg (cfg);
2282 /* add the operands */
2284 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2286 /* Overflow happens if
2287 * neg - pos = pos or
2289 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2291 * tmp1 = (lhs ^ rhs)
2292 * tmp2 = (lhs ^ result)
2293 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2296 /* tmp3 = 1 if the signs of the two inputs differ */
2297 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2298 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2299 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2300 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2301 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2303 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2304 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2305 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2309 case OP_ISUB_OVF_UN:
2310 tmp1 = mono_alloc_ireg (cfg);
2312 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2313 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2314 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2315 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2316 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2323 map_to_reg_reg_op (int op)
2332 case OP_COMPARE_IMM:
2334 case OP_ICOMPARE_IMM:
2336 case OP_LCOMPARE_IMM:
2352 case OP_LOAD_MEMBASE:
2353 return OP_LOAD_MEMINDEX;
2354 case OP_LOADI4_MEMBASE:
2355 return OP_LOADI4_MEMINDEX;
2356 case OP_LOADU4_MEMBASE:
2357 return OP_LOADU4_MEMINDEX;
2358 case OP_LOADU1_MEMBASE:
2359 return OP_LOADU1_MEMINDEX;
2360 case OP_LOADI2_MEMBASE:
2361 return OP_LOADI2_MEMINDEX;
2362 case OP_LOADU2_MEMBASE:
2363 return OP_LOADU2_MEMINDEX;
2364 case OP_LOADI1_MEMBASE:
2365 return OP_LOADI1_MEMINDEX;
2366 case OP_LOADR4_MEMBASE:
2367 return OP_LOADR4_MEMINDEX;
2368 case OP_LOADR8_MEMBASE:
2369 return OP_LOADR8_MEMINDEX;
2370 case OP_STOREI1_MEMBASE_REG:
2371 return OP_STOREI1_MEMINDEX;
2372 case OP_STOREI2_MEMBASE_REG:
2373 return OP_STOREI2_MEMINDEX;
2374 case OP_STOREI4_MEMBASE_REG:
2375 return OP_STOREI4_MEMINDEX;
2376 case OP_STORE_MEMBASE_REG:
2377 return OP_STORE_MEMINDEX;
2378 case OP_STORER4_MEMBASE_REG:
2379 return OP_STORER4_MEMINDEX;
2380 case OP_STORER8_MEMBASE_REG:
2381 return OP_STORER8_MEMINDEX;
2382 case OP_STORE_MEMBASE_IMM:
2383 return OP_STORE_MEMBASE_REG;
2384 case OP_STOREI1_MEMBASE_IMM:
2385 return OP_STOREI1_MEMBASE_REG;
2386 case OP_STOREI2_MEMBASE_IMM:
2387 return OP_STOREI2_MEMBASE_REG;
2388 case OP_STOREI4_MEMBASE_IMM:
2389 return OP_STOREI4_MEMBASE_REG;
2390 case OP_STOREI8_MEMBASE_IMM:
2391 return OP_STOREI8_MEMBASE_REG;
2393 return mono_op_imm_to_op (op);
2397 map_to_mips_op (int op)
2401 return OP_MIPS_FBEQ;
2403 return OP_MIPS_FBGE;
2405 return OP_MIPS_FBGT;
2407 return OP_MIPS_FBLE;
2409 return OP_MIPS_FBLT;
2411 return OP_MIPS_FBNE;
2413 return OP_MIPS_FBGE_UN;
2415 return OP_MIPS_FBGT_UN;
2417 return OP_MIPS_FBLE_UN;
2419 return OP_MIPS_FBLT_UN;
2427 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2428 g_assert_not_reached ();
2432 #define NEW_INS(cfg,after,dest,op) do { \
2433 MONO_INST_NEW((cfg), (dest), (op)); \
2434 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2437 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2439 MONO_INST_NEW(cfg, temp, (op)); \
2440 mono_bblock_insert_after_ins (bb, (pos), temp); \
2441 temp->dreg = (_dreg); \
2442 temp->sreg1 = (_sreg1); \
2443 temp->sreg2 = (_sreg2); \
2447 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2449 MONO_INST_NEW(cfg, temp, (op)); \
2450 mono_bblock_insert_after_ins (bb, (pos), temp); \
2451 temp->dreg = (_dreg); \
2452 temp->sreg1 = (_sreg1); \
2453 temp->inst_c0 = (_imm); \
2458 * Remove from the instruction list the instructions that can't be
2459 * represented with very simple instructions with no register
2463 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2465 MonoInst *ins, *next, *temp, *last_ins = NULL;
2469 if (cfg->verbose_level > 2) {
2472 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2473 MONO_BB_FOR_EACH_INS (bb, ins) {
2474 mono_print_ins_index (idx++, ins);
2480 MONO_BB_FOR_EACH_INS (bb, ins) {
2482 switch (ins->opcode) {
2487 /* Branch opts can eliminate the branch */
2488 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2494 case OP_COMPARE_IMM:
2495 case OP_ICOMPARE_IMM:
2496 case OP_LCOMPARE_IMM:
2498 /* Branch opts can eliminate the branch */
2499 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2503 if (ins->inst_imm) {
2504 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2505 temp->inst_c0 = ins->inst_imm;
2506 temp->dreg = mono_alloc_ireg (cfg);
2507 ins->sreg2 = temp->dreg;
2511 ins->sreg2 = mips_zero;
2513 if (ins->opcode == OP_COMPARE_IMM)
2514 ins->opcode = OP_COMPARE;
2515 else if (ins->opcode == OP_ICOMPARE_IMM)
2516 ins->opcode = OP_ICOMPARE;
2517 else if (ins->opcode == OP_LCOMPARE_IMM)
2518 ins->opcode = OP_LCOMPARE;
2521 case OP_IDIV_UN_IMM:
2524 case OP_IREM_UN_IMM:
2525 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2526 temp->inst_c0 = ins->inst_imm;
2527 temp->dreg = mono_alloc_ireg (cfg);
2528 ins->sreg2 = temp->dreg;
2529 if (ins->opcode == OP_IDIV_IMM)
2530 ins->opcode = OP_IDIV;
2531 else if (ins->opcode == OP_IREM_IMM)
2532 ins->opcode = OP_IREM;
2533 else if (ins->opcode == OP_IDIV_UN_IMM)
2534 ins->opcode = OP_IDIV_UN;
2535 else if (ins->opcode == OP_IREM_UN_IMM)
2536 ins->opcode = OP_IREM_UN;
2538 /* handle rem separately */
2545 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2546 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2547 temp->inst_c0 = ins->inst_imm;
2548 temp->dreg = mono_alloc_ireg (cfg);
2549 ins->sreg2 = temp->dreg;
2550 ins->opcode = map_to_reg_reg_op (ins->opcode);
2560 /* unsigned 16 bit immediate */
2561 if (ins->inst_imm & 0xffff0000) {
2562 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2563 temp->inst_c0 = ins->inst_imm;
2564 temp->dreg = mono_alloc_ireg (cfg);
2565 ins->sreg2 = temp->dreg;
2566 ins->opcode = map_to_reg_reg_op (ins->opcode);
2573 /* signed 16 bit immediate */
2574 if (!mips_is_imm16 (ins->inst_imm)) {
2575 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2576 temp->inst_c0 = ins->inst_imm;
2577 temp->dreg = mono_alloc_ireg (cfg);
2578 ins->sreg2 = temp->dreg;
2579 ins->opcode = map_to_reg_reg_op (ins->opcode);
2585 if (!mips_is_imm16 (-ins->inst_imm)) {
2586 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2587 temp->inst_c0 = ins->inst_imm;
2588 temp->dreg = mono_alloc_ireg (cfg);
2589 ins->sreg2 = temp->dreg;
2590 ins->opcode = map_to_reg_reg_op (ins->opcode);
2596 if (ins->inst_imm == 1) {
2597 ins->opcode = OP_MOVE;
2600 if (ins->inst_imm == 0) {
2601 ins->opcode = OP_ICONST;
2605 imm = mono_is_power_of_two (ins->inst_imm);
2607 ins->opcode = OP_SHL_IMM;
2608 ins->inst_imm = imm;
2611 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2612 temp->inst_c0 = ins->inst_imm;
2613 temp->dreg = mono_alloc_ireg (cfg);
2614 ins->sreg2 = temp->dreg;
2615 ins->opcode = map_to_reg_reg_op (ins->opcode);
2618 case OP_LOCALLOC_IMM:
2619 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2620 temp->inst_c0 = ins->inst_imm;
2621 temp->dreg = mono_alloc_ireg (cfg);
2622 ins->sreg1 = temp->dreg;
2623 ins->opcode = OP_LOCALLOC;
2626 case OP_LOAD_MEMBASE:
2627 case OP_LOADI4_MEMBASE:
2628 case OP_LOADU4_MEMBASE:
2629 case OP_LOADI2_MEMBASE:
2630 case OP_LOADU2_MEMBASE:
2631 case OP_LOADI1_MEMBASE:
2632 case OP_LOADU1_MEMBASE:
2633 case OP_LOADR4_MEMBASE:
2634 case OP_LOADR8_MEMBASE:
2635 case OP_STORE_MEMBASE_REG:
2636 case OP_STOREI4_MEMBASE_REG:
2637 case OP_STOREI2_MEMBASE_REG:
2638 case OP_STOREI1_MEMBASE_REG:
2639 case OP_STORER4_MEMBASE_REG:
2640 case OP_STORER8_MEMBASE_REG:
2641 /* we can do two things: load the immed in a register
2642 * and use an indexed load, or see if the immed can be
2643 * represented as an ad_imm + a load with a smaller offset
2644 * that fits. We just do the first for now, optimize later.
2646 if (mips_is_imm16 (ins->inst_offset))
2648 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2649 temp->inst_c0 = ins->inst_offset;
2650 temp->dreg = mono_alloc_ireg (cfg);
2651 ins->sreg2 = temp->dreg;
2652 ins->opcode = map_to_reg_reg_op (ins->opcode);
2655 case OP_STORE_MEMBASE_IMM:
2656 case OP_STOREI1_MEMBASE_IMM:
2657 case OP_STOREI2_MEMBASE_IMM:
2658 case OP_STOREI4_MEMBASE_IMM:
2659 case OP_STOREI8_MEMBASE_IMM:
2660 if (!ins->inst_imm) {
2661 ins->sreg1 = mips_zero;
2662 ins->opcode = map_to_reg_reg_op (ins->opcode);
2665 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2666 temp->inst_c0 = ins->inst_imm;
2667 temp->dreg = mono_alloc_ireg (cfg);
2668 ins->sreg1 = temp->dreg;
2669 ins->opcode = map_to_reg_reg_op (ins->opcode);
2671 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2677 /* Branch opts can eliminate the branch */
2678 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2685 * remap compare/branch and compare/set
2686 * to MIPS specific opcodes.
2688 next->opcode = map_to_mips_op (next->opcode);
2689 next->sreg1 = ins->sreg1;
2690 next->sreg2 = ins->sreg2;
2697 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2698 temp->inst_c0 = (guint32)ins->inst_p0;
2699 temp->dreg = mono_alloc_ireg (cfg);
2700 ins->inst_basereg = temp->dreg;
2701 ins->inst_offset = 0;
2702 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2704 /* make it handle the possibly big ins->inst_offset
2705 * later optimize to use lis + load_membase
2710 g_assert (ins_is_compare(last_ins));
2711 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2712 NULLIFY_INS(last_ins);
2716 g_assert (ins_is_compare(last_ins));
2717 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2718 NULLIFY_INS(last_ins);
2722 g_assert (ins_is_compare(last_ins));
2723 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2724 last_ins->dreg = mono_alloc_ireg (cfg);
2725 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2729 g_assert (ins_is_compare(last_ins));
2730 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2731 last_ins->dreg = mono_alloc_ireg (cfg);
2732 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2736 g_assert (ins_is_compare(last_ins));
2737 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2738 last_ins->dreg = mono_alloc_ireg (cfg);
2739 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2743 g_assert (ins_is_compare(last_ins));
2744 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2745 last_ins->dreg = mono_alloc_ireg (cfg);
2746 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2750 g_assert (ins_is_compare(last_ins));
2751 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2752 last_ins->dreg = mono_alloc_ireg (cfg);
2753 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2757 g_assert (ins_is_compare(last_ins));
2758 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2759 last_ins->dreg = mono_alloc_ireg (cfg);
2760 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2764 g_assert (ins_is_compare(last_ins));
2765 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2766 last_ins->dreg = mono_alloc_ireg (cfg);
2767 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2771 g_assert (ins_is_compare(last_ins));
2772 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2773 last_ins->dreg = mono_alloc_ireg (cfg);
2774 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2779 g_assert (ins_is_compare(last_ins));
2780 last_ins->opcode = OP_IXOR;
2781 last_ins->dreg = mono_alloc_ireg(cfg);
2782 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2787 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2788 NULLIFY_INS(last_ins);
2794 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2795 NULLIFY_INS(last_ins);
2800 g_assert (ins_is_compare(last_ins));
2801 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2802 MONO_DELETE_INS(bb, last_ins);
2807 g_assert (ins_is_compare(last_ins));
2808 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2809 MONO_DELETE_INS(bb, last_ins);
2812 case OP_COND_EXC_EQ:
2813 case OP_COND_EXC_IEQ:
2814 g_assert (ins_is_compare(last_ins));
2815 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2816 MONO_DELETE_INS(bb, last_ins);
2819 case OP_COND_EXC_GE:
2820 case OP_COND_EXC_IGE:
2821 g_assert (ins_is_compare(last_ins));
2822 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2823 MONO_DELETE_INS(bb, last_ins);
2826 case OP_COND_EXC_GT:
2827 case OP_COND_EXC_IGT:
2828 g_assert (ins_is_compare(last_ins));
2829 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2830 MONO_DELETE_INS(bb, last_ins);
2833 case OP_COND_EXC_LE:
2834 case OP_COND_EXC_ILE:
2835 g_assert (ins_is_compare(last_ins));
2836 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2837 MONO_DELETE_INS(bb, last_ins);
2840 case OP_COND_EXC_LT:
2841 case OP_COND_EXC_ILT:
2842 g_assert (ins_is_compare(last_ins));
2843 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2844 MONO_DELETE_INS(bb, last_ins);
2847 case OP_COND_EXC_NE_UN:
2848 case OP_COND_EXC_INE_UN:
2849 g_assert (ins_is_compare(last_ins));
2850 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2851 MONO_DELETE_INS(bb, last_ins);
2854 case OP_COND_EXC_GE_UN:
2855 case OP_COND_EXC_IGE_UN:
2856 g_assert (ins_is_compare(last_ins));
2857 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2858 MONO_DELETE_INS(bb, last_ins);
2861 case OP_COND_EXC_GT_UN:
2862 case OP_COND_EXC_IGT_UN:
2863 g_assert (ins_is_compare(last_ins));
2864 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2865 MONO_DELETE_INS(bb, last_ins);
2868 case OP_COND_EXC_LE_UN:
2869 case OP_COND_EXC_ILE_UN:
2870 g_assert (ins_is_compare(last_ins));
2871 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2872 MONO_DELETE_INS(bb, last_ins);
2875 case OP_COND_EXC_LT_UN:
2876 case OP_COND_EXC_ILT_UN:
2877 g_assert (ins_is_compare(last_ins));
2878 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2879 MONO_DELETE_INS(bb, last_ins);
2882 case OP_COND_EXC_OV:
2883 case OP_COND_EXC_IOV: {
2884 int tmp1, tmp2, tmp3, tmp4, tmp5;
2885 MonoInst *pos = last_ins;
2887 /* Overflow happens if
2888 * neg + neg = pos or
2891 * (bit31s of operands match) AND (bit31 of operand
2892 * != bit31 of result)
2893 * XOR of the high bit returns 0 if the signs match
2894 * XOR of that with the high bit of the result return 1
2897 g_assert (last_ins->opcode == OP_IADC);
2899 tmp1 = mono_alloc_ireg (cfg);
2900 tmp2 = mono_alloc_ireg (cfg);
2901 tmp3 = mono_alloc_ireg (cfg);
2902 tmp4 = mono_alloc_ireg (cfg);
2903 tmp5 = mono_alloc_ireg (cfg);
2905 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2906 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2908 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2909 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2910 INS (pos, OP_INOT, tmp3, tmp2, -1);
2912 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2913 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2914 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2916 /* Now, if (tmp5 == 0) then overflow */
2917 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2922 case OP_COND_EXC_NO:
2923 case OP_COND_EXC_INO:
2924 g_assert_not_reached ();
2928 case OP_COND_EXC_IC:
2929 g_assert_not_reached ();
2932 case OP_COND_EXC_NC:
2933 case OP_COND_EXC_INC:
2934 g_assert_not_reached ();
2940 bb->last_ins = last_ins;
2941 bb->max_vreg = cfg->next_vreg;
2944 if (cfg->verbose_level > 2) {
2947 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
2948 MONO_BB_FOR_EACH_INS (bb, ins) {
2949 mono_print_ins_index (idx++, ins);
2958 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2960 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
2962 mips_truncwd (code, mips_ftemp, sreg);
2964 mips_cvtwd (code, mips_ftemp, sreg);
2966 mips_mfc1 (code, dreg, mips_ftemp);
2969 mips_andi (code, dreg, dreg, 0xff);
2970 else if (size == 2) {
2971 mips_sll (code, dreg, dreg, 16);
2972 mips_srl (code, dreg, dreg, 16);
2976 mips_sll (code, dreg, dreg, 24);
2977 mips_sra (code, dreg, dreg, 24);
2979 else if (size == 2) {
2980 mips_sll (code, dreg, dreg, 16);
2981 mips_sra (code, dreg, dreg, 16);
2988 * emit_load_volatile_arguments:
2990 * Load volatile arguments from the stack to the original input registers.
2991 * Required before a tail call.
2994 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
2996 MonoMethod *method = cfg->method;
2997 MonoMethodSignature *sig;
3002 sig = mono_method_signature (method);
3003 cinfo = calculate_sizes (sig, sig->pinvoke);
3004 if (cinfo->struct_ret) {
3005 ArgInfo *ainfo = &cinfo->ret;
3006 inst = cfg->vret_addr;
3007 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3010 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3011 ArgInfo *ainfo = cinfo->args + i;
3012 inst = cfg->args [i];
3013 if (inst->opcode == OP_REGVAR) {
3014 if (ainfo->regtype == RegTypeGeneral)
3015 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3016 else if (ainfo->regtype == RegTypeFP)
3017 g_assert_not_reached();
3018 else if (ainfo->regtype == RegTypeBase) {
3021 g_assert_not_reached ();
3023 if (ainfo->regtype == RegTypeGeneral) {
3024 g_assert (mips_is_imm16 (inst->inst_offset));
3025 switch (ainfo->size) {
3027 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3030 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3034 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3037 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3038 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3041 g_assert_not_reached ();
3044 } else if (ainfo->regtype == RegTypeBase) {
3046 } else if (ainfo->regtype == RegTypeFP) {
3047 g_assert (mips_is_imm16 (inst->inst_offset));
3048 if (ainfo->size == 8) {
3049 #if _MIPS_SIM == _ABIO32
3050 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
3051 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
3052 #elif _MIPS_SIM == _ABIN32
3053 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3056 else if (ainfo->size == 4)
3057 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3059 g_assert_not_reached ();
3060 } else if (ainfo->regtype == RegTypeStructByVal) {
3062 int doffset = inst->inst_offset;
3064 g_assert (mips_is_imm16 (inst->inst_offset));
3065 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3066 for (i = 0; i < ainfo->size; ++i) {
3067 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3068 doffset += SIZEOF_REGISTER;
3070 } else if (ainfo->regtype == RegTypeStructByAddr) {
3071 g_assert (mips_is_imm16 (inst->inst_offset));
3072 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3074 g_assert_not_reached ();
3084 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3086 int size = cfg->param_area;
3088 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3089 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3094 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3095 if (ppc_is_imm16 (-size)) {
3096 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3098 ppc_load (code, ppc_r11, -size);
3099 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3106 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3108 int size = cfg->param_area;
3110 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3111 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3116 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3117 if (ppc_is_imm16 (size)) {
3118 ppc_stwu (code, ppc_r0, size, ppc_sp);
3120 ppc_load (code, ppc_r11, size);
3121 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3128 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3133 guint8 *code = cfg->native_code + cfg->code_len;
3134 MonoInst *last_ins = NULL;
3135 guint last_offset = 0;
3139 /* we don't align basic blocks of loops on mips */
3141 if (cfg->verbose_level > 2)
3142 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3144 cpos = bb->max_offset;
3147 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3148 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3149 g_assert (!mono_compile_aot);
3152 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3153 /* this is not thread save, but good enough */
3154 /* fixme: howto handle overflows? */
3155 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3156 mips_lw (code, mips_temp, mips_at, 0);
3157 mips_addiu (code, mips_temp, mips_temp, 1);
3158 mips_sw (code, mips_temp, mips_at, 0);
3161 MONO_BB_FOR_EACH_INS (bb, ins) {
3162 offset = code - cfg->native_code;
3164 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3166 if (offset > (cfg->code_size - max_len - 16)) {
3167 cfg->code_size *= 2;
3168 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3169 code = cfg->native_code + offset;
3171 mono_debug_record_line_number (cfg, ins, offset);
3172 if (cfg->verbose_level > 2) {
3173 g_print (" @ 0x%x\t", offset);
3174 mono_print_ins_index (ins_cnt++, ins);
3176 /* Check for virtual regs that snuck by */
3177 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3179 switch (ins->opcode) {
3180 case OP_RELAXED_NOP:
3183 case OP_DUMMY_STORE:
3184 case OP_NOT_REACHED:
3188 g_assert_not_reached();
3190 emit_tls_access (code, ins->dreg, ins->inst_offset);
3194 mips_mult (code, ins->sreg1, ins->sreg2);
3195 mips_mflo (code, ins->dreg);
3196 mips_mfhi (code, ins->dreg+1);
3199 mips_multu (code, ins->sreg1, ins->sreg2);
3200 mips_mflo (code, ins->dreg);
3201 mips_mfhi (code, ins->dreg+1);
3203 case OP_MEMORY_BARRIER:
3208 case OP_STOREI1_MEMBASE_IMM:
3209 mips_load_const (code, mips_temp, ins->inst_imm);
3210 if (mips_is_imm16 (ins->inst_offset)) {
3211 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3213 mips_load_const (code, mips_at, ins->inst_offset);
3214 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3217 case OP_STOREI2_MEMBASE_IMM:
3218 mips_load_const (code, mips_temp, ins->inst_imm);
3219 if (mips_is_imm16 (ins->inst_offset)) {
3220 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3222 mips_load_const (code, mips_at, ins->inst_offset);
3223 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3226 case OP_STOREI8_MEMBASE_IMM:
3227 mips_load_const (code, mips_temp, ins->inst_imm);
3228 if (mips_is_imm16 (ins->inst_offset)) {
3229 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3231 mips_load_const (code, mips_at, ins->inst_offset);
3232 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3235 case OP_STORE_MEMBASE_IMM:
3236 case OP_STOREI4_MEMBASE_IMM:
3237 mips_load_const (code, mips_temp, ins->inst_imm);
3238 if (mips_is_imm16 (ins->inst_offset)) {
3239 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3241 mips_load_const (code, mips_at, ins->inst_offset);
3242 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3245 case OP_STOREI1_MEMBASE_REG:
3246 if (mips_is_imm16 (ins->inst_offset)) {
3247 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3249 mips_load_const (code, mips_at, ins->inst_offset);
3250 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3251 mips_sb (code, ins->sreg1, mips_at, 0);
3254 case OP_STOREI2_MEMBASE_REG:
3255 if (mips_is_imm16 (ins->inst_offset)) {
3256 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3258 mips_load_const (code, mips_at, ins->inst_offset);
3259 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3260 mips_sh (code, ins->sreg1, mips_at, 0);
3263 case OP_STORE_MEMBASE_REG:
3264 case OP_STOREI4_MEMBASE_REG:
3265 if (mips_is_imm16 (ins->inst_offset)) {
3266 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3268 mips_load_const (code, mips_at, ins->inst_offset);
3269 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3270 mips_sw (code, ins->sreg1, mips_at, 0);
3273 case OP_STOREI8_MEMBASE_REG:
3274 if (mips_is_imm16 (ins->inst_offset)) {
3275 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3277 mips_load_const (code, mips_at, ins->inst_offset);
3278 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3279 mips_sd (code, ins->sreg1, mips_at, 0);
3283 g_assert_not_reached ();
3284 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3285 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3287 case OP_LOADI8_MEMBASE:
3288 if (mips_is_imm16 (ins->inst_offset)) {
3289 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3291 mips_load_const (code, mips_at, ins->inst_offset);
3292 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3293 mips_ld (code, ins->dreg, mips_at, 0);
3296 case OP_LOAD_MEMBASE:
3297 case OP_LOADI4_MEMBASE:
3298 case OP_LOADU4_MEMBASE:
3299 g_assert (ins->dreg != -1);
3300 if (mips_is_imm16 (ins->inst_offset)) {
3301 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3303 mips_load_const (code, mips_at, ins->inst_offset);
3304 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3305 mips_lw (code, ins->dreg, mips_at, 0);
3308 case OP_LOADI1_MEMBASE:
3309 if (mips_is_imm16 (ins->inst_offset)) {
3310 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3312 mips_load_const (code, mips_at, ins->inst_offset);
3313 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3314 mips_lb (code, ins->dreg, mips_at, 0);
3317 case OP_LOADU1_MEMBASE:
3318 if (mips_is_imm16 (ins->inst_offset)) {
3319 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3321 mips_load_const (code, mips_at, ins->inst_offset);
3322 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3323 mips_lbu (code, ins->dreg, mips_at, 0);
3326 case OP_LOADI2_MEMBASE:
3327 if (mips_is_imm16 (ins->inst_offset)) {
3328 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3330 mips_load_const (code, mips_at, ins->inst_offset);
3331 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3332 mips_lh (code, ins->dreg, mips_at, 0);
3335 case OP_LOADU2_MEMBASE:
3336 if (mips_is_imm16 (ins->inst_offset)) {
3337 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3339 mips_load_const (code, mips_at, ins->inst_offset);
3340 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3341 mips_lhu (code, ins->dreg, mips_at, 0);
3344 case OP_ICONV_TO_I1:
3345 mips_sll (code, mips_at, ins->sreg1, 24);
3346 mips_sra (code, ins->dreg, mips_at, 24);
3348 case OP_ICONV_TO_I2:
3349 mips_sll (code, mips_at, ins->sreg1, 16);
3350 mips_sra (code, ins->dreg, mips_at, 16);
3352 case OP_ICONV_TO_U1:
3353 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3355 case OP_ICONV_TO_U2:
3356 mips_sll (code, mips_at, ins->sreg1, 16);
3357 mips_srl (code, ins->dreg, mips_at, 16);
3360 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3363 g_assert (mips_is_imm16 (ins->inst_imm));
3364 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3367 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3370 g_assert (mips_is_imm16 (ins->inst_imm));
3371 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3374 mips_break (code, 0xfd);
3377 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3380 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3385 g_assert (mips_is_imm16 (ins->inst_imm));
3386 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3389 g_assert (mips_is_imm16 (ins->inst_imm));
3390 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3394 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3397 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3402 // we add the negated value
3403 g_assert (mips_is_imm16 (-ins->inst_imm));
3404 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3408 // we add the negated value
3409 g_assert (mips_is_imm16 (-ins->inst_imm));
3410 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3415 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3421 g_assert (!(ins->inst_imm & 0xffff0000));
3422 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3427 guint32 *divisor_is_m1;
3428 guint32 *divisor_is_zero;
3431 mips_addiu (code, mips_at, mips_zero, 0xffff);
3432 divisor_is_m1 = (guint32 *)(void *)code;
3433 mips_bne (code, ins->sreg2, mips_at, 0);
3436 /* Divide by -1 -- throw exception */
3437 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
3439 mips_patch (divisor_is_m1, (guint32)code);
3441 /* Put divide in branch delay slot (NOT YET) */
3442 divisor_is_zero = (guint32 *)(void *)code;
3443 mips_bne (code, ins->sreg2, mips_zero, 0);
3446 /* Divide by zero -- throw exception */
3447 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3449 mips_patch (divisor_is_zero, (guint32)code);
3450 mips_div (code, ins->sreg1, ins->sreg2);
3451 if (ins->opcode == OP_IDIV)
3452 mips_mflo (code, ins->dreg);
3454 mips_mfhi (code, ins->dreg);
3459 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3461 /* Put divide in branch delay slot (NOT YET) */
3462 mips_bne (code, ins->sreg2, mips_zero, 0);
3465 /* Divide by zero -- throw exception */
3466 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3468 mips_patch (divisor_is_zero, (guint32)code);
3469 mips_divu (code, ins->sreg1, ins->sreg2);
3470 if (ins->opcode == OP_IDIV_UN)
3471 mips_mflo (code, ins->dreg);
3473 mips_mfhi (code, ins->dreg);
3477 g_assert_not_reached ();
3479 ppc_load (code, ppc_r11, ins->inst_imm);
3480 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3481 ppc_mfspr (code, ppc_r0, ppc_xer);
3482 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3483 /* FIXME: use OverflowException for 0x80000000/-1 */
3484 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3486 g_assert_not_reached();
3489 g_assert_not_reached ();
3491 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3495 g_assert (!(ins->inst_imm & 0xffff0000));
3496 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3499 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3503 /* unsigned 16-bit immediate */
3504 g_assert (!(ins->inst_imm & 0xffff0000));
3505 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3508 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3512 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3515 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3518 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3522 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3525 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3528 case OP_ISHR_UN_IMM:
3529 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3531 case OP_LSHR_UN_IMM:
3532 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3535 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3538 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3542 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3545 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3548 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3552 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3554 mips_mult (code, ins->sreg1, ins->sreg2);
3555 mips_mflo (code, ins->dreg);
3560 #if SIZEOF_REGISTER == 8
3562 mips_dmult (code, ins->sreg1, ins->sreg2);
3563 mips_mflo (code, ins->dreg);
3568 mips_mult (code, ins->sreg1, ins->sreg2);
3569 mips_mflo (code, ins->dreg);
3570 mips_mfhi (code, mips_at);
3573 mips_sra (code, mips_temp, ins->dreg, 31);
3574 patch = (guint32 *)(void *)code;
3575 mips_beq (code, mips_temp, mips_at, 0);
3577 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3578 mips_patch (patch, (guint32)code);
3581 case OP_IMUL_OVF_UN: {
3583 mips_mult (code, ins->sreg1, ins->sreg2);
3584 mips_mflo (code, ins->dreg);
3585 mips_mfhi (code, mips_at);
3588 patch = (guint32 *)(void *)code;
3589 mips_beq (code, mips_at, mips_zero, 0);
3591 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3592 mips_patch (patch, (guint32)code);
3596 mips_load_const (code, ins->dreg, ins->inst_c0);
3598 #if SIZEOF_REGISTER == 8
3600 mips_load_const (code, ins->dreg, ins->inst_c0);
3604 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3605 mips_load (code, ins->dreg, 0);
3609 mips_mtc1 (code, ins->dreg, ins->sreg1);
3611 case OP_MIPS_MTC1S_2:
3612 mips_mtc1 (code, ins->dreg, ins->sreg1);
3613 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3616 mips_mfc1 (code, ins->dreg, ins->sreg1);
3619 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3623 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3625 mips_mfc1 (code, ins->dreg+1, ins->sreg1);
3626 mips_mfc1 (code, ins->dreg, ins->sreg1+1);
3630 case OP_ICONV_TO_I4:
3631 case OP_ICONV_TO_U4:
3633 if (ins->dreg != ins->sreg1)
3634 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3636 #if SIZEOF_REGISTER == 8
3638 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3639 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3642 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3643 mips_dsra (code, ins->dreg, ins->dreg, 32);
3647 /* Get sreg1 into v1, sreg2 into v0 */
3649 if (ins->sreg1 == mips_v0) {
3650 if (ins->sreg1 != mips_at)
3651 MIPS_MOVE (code, mips_at, ins->sreg1);
3652 if (ins->sreg2 != mips_v0)
3653 MIPS_MOVE (code, mips_v0, ins->sreg2);
3654 MIPS_MOVE (code, mips_v1, mips_at);
3657 if (ins->sreg2 != mips_v0)
3658 MIPS_MOVE (code, mips_v0, ins->sreg2);
3659 if (ins->sreg1 != mips_v1)
3660 MIPS_MOVE (code, mips_v1, ins->sreg1);
3664 if (ins->dreg != ins->sreg1) {
3665 mips_fmovd (code, ins->dreg, ins->sreg1);
3669 /* Convert from double to float and leave it there */
3670 mips_cvtsd (code, ins->dreg, ins->sreg1);
3672 case OP_FCONV_TO_R4:
3674 mips_cvtsd (code, ins->dreg, ins->sreg1);
3676 /* Just a move, no precision change */
3677 if (ins->dreg != ins->sreg1) {
3678 mips_fmovd (code, ins->dreg, ins->sreg1);
3683 code = emit_load_volatile_arguments(cfg, code);
3686 * Pop our stack, then jump to specified method (tail-call)
3687 * Keep in sync with mono_arch_emit_epilog
3689 code = mono_arch_emit_epilog_sub (cfg, code);
3691 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3692 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3693 if (cfg->arch.long_branch) {
3694 mips_lui (code, mips_t9, mips_zero, 0);
3695 mips_addiu (code, mips_t9, mips_t9, 0);
3696 mips_jr (code, mips_t9);
3700 mips_beq (code, mips_zero, mips_zero, 0);
3705 /* ensure ins->sreg1 is not NULL */
3706 mips_lw (code, mips_zero, ins->sreg1, 0);
3709 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3710 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3712 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
3713 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
3715 mips_sw (code, mips_at, ins->sreg1, 0);
3728 case OP_VOIDCALL_REG:
3730 case OP_FCALL_MEMBASE:
3731 case OP_LCALL_MEMBASE:
3732 case OP_VCALL_MEMBASE:
3733 case OP_VCALL2_MEMBASE:
3734 case OP_VOIDCALL_MEMBASE:
3735 case OP_CALL_MEMBASE:
3736 call = (MonoCallInst*)ins;
3737 switch (ins->opcode) {
3744 if (ins->flags & MONO_INST_HAS_METHOD) {
3745 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3746 mips_call (code, mips_t9, call->method);
3749 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3750 mips_call (code, mips_t9, call->fptr);
3757 case OP_VOIDCALL_REG:
3759 MIPS_MOVE (code, mips_t9, ins->sreg1);
3760 mips_jalr (code, mips_t9, mips_ra);
3763 case OP_FCALL_MEMBASE:
3764 case OP_LCALL_MEMBASE:
3765 case OP_VCALL_MEMBASE:
3766 case OP_VCALL2_MEMBASE:
3767 case OP_VOIDCALL_MEMBASE:
3768 case OP_CALL_MEMBASE:
3769 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3770 mips_jalr (code, mips_t9, mips_ra);
3774 #if PROMOTE_R4_TO_R8
3775 /* returned an FP R4 (single), promote to R8 (double) in place */
3776 if ((ins->opcode == OP_FCALL ||
3777 ins->opcode == OP_FCALL_REG) &&
3778 call->signature->ret->type == MONO_TYPE_R4) {
3779 mips_cvtds (code, mips_f0, mips_f0);
3784 int area_offset = cfg->param_area;
3786 /* Round up ins->sreg1, mips_at ends up holding size */
3787 mips_addiu (code, mips_at, ins->sreg1, 31);
3788 mips_addiu (code, mips_temp, mips_zero, ~31);
3789 mips_and (code, mips_at, mips_at, mips_temp);
3791 mips_subu (code, mips_sp, mips_sp, mips_at);
3792 g_assert (mips_is_imm16 (area_offset));
3793 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3795 if (ins->flags & MONO_INST_INIT) {
3796 mips_move (code, mips_temp, ins->dreg);
3797 mips_sb (code, mips_zero, mips_temp, 0);
3798 mips_addiu (code, mips_at, mips_at, -1);
3799 mips_bne (code, mips_at, mips_zero, -3);
3800 mips_addiu (code, mips_temp, mips_temp, 1);
3805 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3806 mips_move (code, mips_a0, ins->sreg1);
3807 mips_call (code, mips_t9, addr);
3808 mips_break (code, 0xfc);
3812 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3813 mips_move (code, mips_a0, ins->sreg1);
3814 mips_call (code, mips_t9, addr);
3815 mips_break (code, 0xfb);
3818 case OP_START_HANDLER: {
3820 * The START_HANDLER instruction marks the beginning of
3821 * a handler block. It is called using a call
3822 * instruction, so mips_ra contains the return address.
3823 * Since the handler executes in the same stack frame
3824 * as the method itself, we can't use save/restore to
3825 * save the return address. Instead, we save it into
3826 * a dedicated variable.
3828 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3829 g_assert (spvar->inst_basereg != mips_sp);
3830 code = emit_reserve_param_area (cfg, code);
3832 if (mips_is_imm16 (spvar->inst_offset)) {
3833 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3835 mips_load_const (code, mips_at, spvar->inst_offset);
3836 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3837 mips_sw (code, mips_ra, mips_at, 0);
3841 case OP_ENDFILTER: {
3842 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3843 g_assert (spvar->inst_basereg != mips_sp);
3844 code = emit_unreserve_param_area (cfg, code);
3846 if (ins->sreg1 != mips_v0)
3847 MIPS_MOVE (code, mips_v0, ins->sreg1);
3848 if (mips_is_imm16 (spvar->inst_offset)) {
3849 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3851 mips_load_const (code, mips_at, spvar->inst_offset);
3852 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3853 mips_lw (code, mips_ra, mips_at, 0);
3855 mips_jr (code, mips_ra);
3859 case OP_ENDFINALLY: {
3860 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3861 g_assert (spvar->inst_basereg != mips_sp);
3862 code = emit_unreserve_param_area (cfg, code);
3863 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3864 mips_jalr (code, mips_t9, mips_ra);
3868 case OP_CALL_HANDLER:
3869 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3870 mips_lui (code, mips_t9, mips_zero, 0);
3871 mips_addiu (code, mips_t9, mips_t9, 0);
3872 mips_jalr (code, mips_t9, mips_ra);
3874 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3875 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3878 ins->inst_c0 = code - cfg->native_code;
3881 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3882 if (cfg->arch.long_branch) {
3883 mips_lui (code, mips_at, mips_zero, 0);
3884 mips_addiu (code, mips_at, mips_at, 0);
3885 mips_jr (code, mips_at);
3889 mips_beq (code, mips_zero, mips_zero, 0);
3894 mips_jr (code, ins->sreg1);
3900 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3901 if (offset > (cfg->code_size - max_len - 16)) {
3902 cfg->code_size += max_len;
3903 cfg->code_size *= 2;
3904 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3905 code = cfg->native_code + offset;
3907 g_assert (ins->sreg1 != -1);
3908 mips_sll (code, mips_at, ins->sreg1, 2);
3909 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3910 MIPS_MOVE (code, mips_t8, mips_ra);
3911 mips_bgezal (code, mips_zero, 1); /* bal */
3913 mips_addu (code, mips_t9, mips_ra, mips_at);
3914 /* Table is 16 or 20 bytes from target of bal above */
3915 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3916 MIPS_MOVE (code, mips_ra, mips_t8);
3917 mips_lw (code, mips_t9, mips_t9, 20);
3920 mips_lw (code, mips_t9, mips_t9, 16);
3921 mips_jalr (code, mips_t9, mips_t8);
3923 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3924 mips_emit32 (code, 0xfefefefe);
3929 mips_addiu (code, ins->dreg, mips_zero, 1);
3930 mips_beq (code, mips_at, mips_zero, 2);
3932 MIPS_MOVE (code, ins->dreg, mips_zero);
3938 mips_addiu (code, ins->dreg, mips_zero, 1);
3939 mips_bltz (code, mips_at, 2);
3941 MIPS_MOVE (code, ins->dreg, mips_zero);
3947 mips_addiu (code, ins->dreg, mips_zero, 1);
3948 mips_bgtz (code, mips_at, 2);
3950 MIPS_MOVE (code, ins->dreg, mips_zero);
3953 case OP_MIPS_COND_EXC_EQ:
3954 case OP_MIPS_COND_EXC_GE:
3955 case OP_MIPS_COND_EXC_GT:
3956 case OP_MIPS_COND_EXC_LE:
3957 case OP_MIPS_COND_EXC_LT:
3958 case OP_MIPS_COND_EXC_NE_UN:
3959 case OP_MIPS_COND_EXC_GE_UN:
3960 case OP_MIPS_COND_EXC_GT_UN:
3961 case OP_MIPS_COND_EXC_LE_UN:
3962 case OP_MIPS_COND_EXC_LT_UN:
3964 case OP_MIPS_COND_EXC_OV:
3965 case OP_MIPS_COND_EXC_NO:
3966 case OP_MIPS_COND_EXC_C:
3967 case OP_MIPS_COND_EXC_NC:
3969 case OP_MIPS_COND_EXC_IEQ:
3970 case OP_MIPS_COND_EXC_IGE:
3971 case OP_MIPS_COND_EXC_IGT:
3972 case OP_MIPS_COND_EXC_ILE:
3973 case OP_MIPS_COND_EXC_ILT:
3974 case OP_MIPS_COND_EXC_INE_UN:
3975 case OP_MIPS_COND_EXC_IGE_UN:
3976 case OP_MIPS_COND_EXC_IGT_UN:
3977 case OP_MIPS_COND_EXC_ILE_UN:
3978 case OP_MIPS_COND_EXC_ILT_UN:
3980 case OP_MIPS_COND_EXC_IOV:
3981 case OP_MIPS_COND_EXC_INO:
3982 case OP_MIPS_COND_EXC_IC:
3983 case OP_MIPS_COND_EXC_INC: {
3987 /* If the condition is true, raise the exception */
3989 /* need to reverse test to skip around exception raising */
3991 /* For the moment, branch around a branch to avoid reversing
3994 /* Remember, an unpatched branch to 0 branches to the delay slot */
3995 switch (ins->opcode) {
3996 case OP_MIPS_COND_EXC_EQ:
3997 throw = (guint32 *)(void *)code;
3998 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4002 case OP_MIPS_COND_EXC_NE_UN:
4003 throw = (guint32 *)(void *)code;
4004 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4008 case OP_MIPS_COND_EXC_LE_UN:
4009 mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
4010 throw = (guint32 *)(void *)code;
4011 mips_blez (code, mips_at, 0);
4015 case OP_MIPS_COND_EXC_GT:
4016 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4017 throw = (guint32 *)(void *)code;
4018 mips_bne (code, mips_at, mips_zero, 0);
4022 case OP_MIPS_COND_EXC_GT_UN:
4023 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4024 throw = (guint32 *)(void *)code;
4025 mips_bne (code, mips_at, mips_zero, 0);
4029 case OP_MIPS_COND_EXC_LT:
4030 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4031 throw = (guint32 *)(void *)code;
4032 mips_bne (code, mips_at, mips_zero, 0);
4036 case OP_MIPS_COND_EXC_LT_UN:
4037 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4038 throw = (guint32 *)(void *)code;
4039 mips_bne (code, mips_at, mips_zero, 0);
4044 /* Not yet implemented */
4045 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4046 g_assert_not_reached ();
4048 skip = (guint32 *)(void *)code;
4049 mips_beq (code, mips_zero, mips_zero, 0);
4051 mips_patch (throw, (guint32)code);
4052 code = mips_emit_exc_by_name (code, ins->inst_p1);
4053 mips_patch (skip, (guint32)code);
4054 cfg->bb_exit->max_offset += 24;
4063 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4066 /* floating point opcodes */
4069 if (((guint32)ins->inst_p0) & (1 << 15))
4070 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4072 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4073 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4075 mips_load_const (code, mips_at, ins->inst_p0);
4076 mips_lwc1 (code, ins->dreg, mips_at, 4);
4077 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4081 if (((guint32)ins->inst_p0) & (1 << 15))
4082 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4084 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4085 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4086 #if PROMOTE_R4_TO_R8
4087 mips_cvtds (code, ins->dreg, ins->dreg);
4090 case OP_STORER8_MEMBASE_REG:
4091 if (mips_is_imm16 (ins->inst_offset)) {
4092 #if _MIPS_SIM == _ABIO32
4093 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
4094 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
4095 #elif _MIPS_SIM == _ABIN32
4096 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4099 mips_load_const (code, mips_at, ins->inst_offset);
4100 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4101 mips_swc1 (code, ins->sreg1, mips_at, 4);
4102 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
4105 case OP_LOADR8_MEMBASE:
4106 if (mips_is_imm16 (ins->inst_offset)) {
4107 #if _MIPS_SIM == _ABIO32
4108 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
4109 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
4110 #elif _MIPS_SIM == _ABIN32
4111 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4114 mips_load_const (code, mips_at, ins->inst_offset);
4115 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4116 mips_lwc1 (code, ins->dreg, mips_at, 4);
4117 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4120 case OP_STORER4_MEMBASE_REG:
4121 g_assert (mips_is_imm16 (ins->inst_offset));
4122 #if PROMOTE_R4_TO_R8
4123 /* Need to convert ins->sreg1 to single-precision first */
4124 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4125 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4127 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4131 g_assert (mips_is_imm16 (ins->inst_offset));
4132 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4134 case OP_LOADR4_MEMBASE:
4135 g_assert (mips_is_imm16 (ins->inst_offset));
4136 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4137 #if PROMOTE_R4_TO_R8
4138 /* Convert to double precision in place */
4139 mips_cvtds (code, ins->dreg, ins->dreg);
4142 case OP_LOADR4_MEMINDEX:
4143 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4144 mips_lwc1 (code, ins->dreg, mips_at, 0);
4146 case OP_LOADR8_MEMINDEX:
4147 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4148 #if _MIPS_SIM == _ABIO32
4149 mips_lwc1 (code, ins->dreg, mips_at, 0);
4150 mips_lwc1 (code, ins->dreg+1, mips_at, 4);
4151 #elif _MIPS_SIM == _ABIN32
4152 mips_ldc1 (code, ins->dreg, mips_at, 0);
4155 case OP_STORER4_MEMINDEX:
4156 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4157 #if PROMOTE_R4_TO_R8
4158 /* Need to convert ins->sreg1 to single-precision first */
4159 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4160 mips_swc1 (code, mips_ftemp, mips_at, 0);
4162 mips_swc1 (code, ins->sreg1, mips_at, 0);
4165 case OP_STORER8_MEMINDEX:
4166 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4167 #if _MIPS_SIM == _ABIO32
4168 mips_swc1 (code, ins->sreg1, mips_at, 0);
4169 mips_swc1 (code, ins->sreg1+1, mips_at, 4);
4170 #elif _MIPS_SIM == _ABIN32
4171 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4174 case OP_ICONV_TO_R_UN: {
4175 static const guint64 adjust_val = 0x41F0000000000000ULL;
4177 /* convert unsigned int to double */
4178 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4179 mips_bgez (code, ins->sreg1, 5);
4180 mips_cvtdw (code, ins->dreg, mips_ftemp);
4182 mips_load (code, mips_at, (guint32) &adjust_val);
4183 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4184 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4185 /* target is here */
4188 case OP_ICONV_TO_R4:
4189 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4190 mips_cvtsw (code, ins->dreg, mips_ftemp);
4191 mips_cvtds (code, ins->dreg, ins->dreg);
4193 case OP_ICONV_TO_R8:
4194 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4195 mips_cvtdw (code, ins->dreg, mips_ftemp);
4197 case OP_FCONV_TO_I1:
4198 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4200 case OP_FCONV_TO_U1:
4201 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4203 case OP_FCONV_TO_I2:
4204 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4206 case OP_FCONV_TO_U2:
4207 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4209 case OP_FCONV_TO_I4:
4211 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4213 case OP_FCONV_TO_U4:
4215 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4218 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4221 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4224 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4227 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4230 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4233 mips_fnegd (code, ins->dreg, ins->sreg1);
4236 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4237 mips_addiu (code, ins->dreg, mips_zero, 1);
4238 mips_fbtrue (code, 2);
4240 MIPS_MOVE (code, ins->dreg, mips_zero);
4243 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4244 mips_addiu (code, ins->dreg, mips_zero, 1);
4245 mips_fbtrue (code, 2);
4247 MIPS_MOVE (code, ins->dreg, mips_zero);
4250 /* Less than, or Unordered */
4251 mips_fcmpd (code, MIPS_FPU_ULT, 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 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4259 MIPS_MOVE (code, ins->dreg, mips_zero);
4260 mips_fbtrue (code, 2);
4262 mips_addiu (code, ins->dreg, mips_zero, 1);
4265 /* Greater than, or Unordered */
4266 mips_fcmpd (code, MIPS_FPU_OLE, 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 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4275 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4276 mips_fbtrue (code, 0);
4280 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4282 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4283 mips_fbfalse (code, 0);
4287 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4289 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4290 mips_fbtrue (code, 0);
4293 case OP_MIPS_FBLT_UN:
4294 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4296 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4297 mips_fbtrue (code, 0);
4301 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
4303 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4304 mips_fbfalse (code, 0);
4307 case OP_MIPS_FBGT_UN:
4308 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4310 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4311 mips_fbfalse (code, 0);
4315 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4317 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4318 mips_fbfalse (code, 0);
4321 case OP_MIPS_FBGE_UN:
4322 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
4324 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4325 mips_fbfalse (code, 0);
4329 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4331 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4332 mips_fbtrue (code, 0);
4335 case OP_MIPS_FBLE_UN:
4336 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4338 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4339 mips_fbtrue (code, 0);
4343 guint32 *branch_patch;
4345 mips_mfc1 (code, mips_at, ins->sreg1+1);
4346 mips_srl (code, mips_at, mips_at, 16+4);
4347 mips_andi (code, mips_at, mips_at, 2047);
4348 mips_addiu (code, mips_at, mips_at, -2047);
4350 branch_patch = (guint32 *)(void *)code;
4351 mips_bne (code, mips_at, mips_zero, 0);
4354 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4355 mips_patch (branch_patch, (guint32)code);
4356 mips_fmovd (code, ins->dreg, ins->sreg1);
4360 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4361 mips_load (code, ins->dreg, 0x0f0f0f0f);
4366 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4367 g_assert_not_reached ();
4370 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4371 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4372 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4373 g_assert_not_reached ();
4379 last_offset = offset;
4382 cfg->code_len = code - cfg->native_code;
4386 mono_arch_register_lowlevel_calls (void)
4391 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4393 MonoJumpInfo *patch_info;
4395 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4396 unsigned char *ip = patch_info->ip.i + code;
4397 const unsigned char *target = NULL;
4399 switch (patch_info->type) {
4400 case MONO_PATCH_INFO_IP:
4401 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4403 case MONO_PATCH_INFO_SWITCH: {
4404 gpointer *table = (gpointer *)patch_info->data.table->table;
4407 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4409 for (i = 0; i < patch_info->data.table->table_size; i++) {
4410 table [i] = (int)patch_info->data.table->table [i] + code;
4414 case MONO_PATCH_INFO_METHODCONST:
4415 case MONO_PATCH_INFO_CLASS:
4416 case MONO_PATCH_INFO_IMAGE:
4417 case MONO_PATCH_INFO_FIELD:
4418 case MONO_PATCH_INFO_VTABLE:
4419 case MONO_PATCH_INFO_IID:
4420 case MONO_PATCH_INFO_SFLDA:
4421 case MONO_PATCH_INFO_LDSTR:
4422 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4423 case MONO_PATCH_INFO_LDTOKEN:
4424 case MONO_PATCH_INFO_R4:
4425 case MONO_PATCH_INFO_R8:
4426 /* from OP_AOTCONST : lui + addiu */
4427 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4428 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4431 case MONO_PATCH_INFO_EXC_NAME:
4432 g_assert_not_reached ();
4433 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4436 case MONO_PATCH_INFO_NONE:
4437 /* everything is dealt with at epilog output time */
4440 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4441 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4450 mono_trace_lmf_prolog (MonoLMF *new_lmf)
4456 mono_trace_lmf_epilog (MonoLMF *old_lmf)
4462 * Allow tracing to work with this interface (with an optional argument)
4464 * This code is expected to be inserted just after the 'real' prolog code,
4465 * and before the first basic block. We need to allocate a 2nd, temporary
4466 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4470 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4473 int offset = cfg->arch.tracing_offset;
4479 /* For N32, need to know for each stack slot if it's an integer
4480 * or float argument, and save/restore the appropriate register
4482 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4483 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4484 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4485 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4486 #if _MIPS_SIM == _ABIN32
4487 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4488 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4489 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4490 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4493 mips_load_const (code, mips_a0, cfg->method);
4494 mips_addiu (code, mips_a1, mips_sp, offset);
4495 mips_call (code, mips_t9, func);
4497 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4498 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4499 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4500 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4501 #if _MIPS_SIM == _ABIN32
4502 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4503 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4504 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4505 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4515 mips_adjust_stackframe(MonoCompile *cfg)
4518 int delta, threshold, i;
4519 MonoMethodSignature *sig;
4522 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4525 /* adjust cfg->stack_offset for account for down-spilling */
4526 cfg->stack_offset += SIZEOF_REGISTER;
4528 /* re-align cfg->stack_offset if needed (due to var spilling) */
4529 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4530 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4531 if (cfg->verbose_level > 2) {
4532 g_print ("mips_adjust_stackframe:\n");
4533 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4535 threshold = cfg->arch.local_alloc_offset;
4536 ra_offset = cfg->stack_offset - sizeof(gpointer);
4537 if (cfg->verbose_level > 2) {
4538 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4541 sig = mono_method_signature (cfg->method);
4542 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4543 cfg->vret_addr->inst_offset += delta;
4545 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4546 MonoInst *inst = cfg->args [i];
4548 inst->inst_offset += delta;
4552 * loads and stores based off the frame reg that (used to) lie
4553 * above the spill var area need to be increased by 'delta'
4554 * to make room for the spill vars.
4556 /* Need to find loads and stores to adjust that
4557 * are above where the spillvars were inserted, but
4558 * which are not the spillvar references themselves.
4560 * Idea - since all offsets from fp are positive, make
4561 * spillvar offsets negative to begin with so we can spot
4566 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4570 if (cfg->verbose_level > 2) {
4571 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4573 MONO_BB_FOR_EACH_INS (bb, ins) {
4577 if (cfg->verbose_level > 2) {
4578 mono_print_ins_index (ins_cnt, ins);
4580 if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp))
4582 if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))
4584 /* The following two catch FP spills */
4585 if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_sp))
4587 if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_sp))
4589 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4592 if (ins->inst_c0 >= threshold) {
4593 ins->inst_c0 += delta;
4594 if (cfg->verbose_level > 2) {
4596 mono_print_ins_index (ins_cnt, ins);
4599 else if (ins->inst_c0 < 0) {
4600 ins->inst_c0 = - ins->inst_c0 - 4;
4601 if (cfg->verbose_level > 2) {
4603 mono_print_ins_index (ins_cnt, ins);
4606 g_assert (ins->inst_c0 != ra_offset);
4609 if (ins->inst_imm >= threshold) {
4610 ins->inst_imm += delta;
4611 if (cfg->verbose_level > 2) {
4613 mono_print_ins_index (ins_cnt, ins);
4616 g_assert (ins->inst_c0 != ra_offset);
4626 * Stack frame layout:
4628 * ------------------- sp + cfg->stack_usage + cfg->param_area
4629 * param area incoming
4630 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4632 * ------------------- sp + cfg->stack_usage
4634 * ------------------- sp + cfg->stack_usage-4
4636 * ------------------- sp +
4637 * MonoLMF structure optional
4638 * ------------------- sp + cfg->arch.lmf_offset
4639 * saved registers s0-s8
4640 * ------------------- sp + cfg->arch.iregs_offset
4642 * ------------------- sp + cfg->param_area
4643 * param area outgoing
4644 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4646 * ------------------- sp
4650 mono_arch_emit_prolog (MonoCompile *cfg)
4652 MonoMethod *method = cfg->method;
4653 MonoMethodSignature *sig;
4655 int alloc_size, pos, i;
4656 int alloc2_size = 0;
4660 guint32 iregs_to_save = 0;
4662 guint32 fregs_to_save = 0;
4665 /* lmf_offset is the offset of the LMF from our stack pointer. */
4666 guint32 lmf_offset = cfg->arch.lmf_offset;
4669 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4673 cfg->flags |= MONO_CFG_HAS_CALLS;
4675 sig = mono_method_signature (method);
4676 cfg->code_size = 768 + sig->param_count * 20;
4677 code = cfg->native_code = g_malloc (cfg->code_size);
4680 #if _MIPS_SIM == _ABIO32
4681 cfg->arch.tracing_offset = cfg->stack_offset;
4682 #elif _MIPS_SIM == _ABIN32
4683 /* no stack slots by default for argument regs, reserve a special block */
4684 cfg->arch.tracing_offset = cfg->stack_offset;
4685 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4689 /* adjust stackframe assignments for spillvars if needed */
4690 mips_adjust_stackframe (cfg);
4692 /* stack_offset should not be changed here. */
4693 alloc_size = cfg->stack_offset;
4694 cfg->stack_usage = alloc_size;
4697 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4699 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4703 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4705 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4706 fregs_to_save |= (fregs_to_save << 1);
4709 /* If the stack size is too big, save 1024 bytes to start with
4710 * so the prologue can use imm16(reg) addressing, then allocate
4711 * the rest of the frame.
4713 if (alloc_size > ((1 << 15) - 1024)) {
4714 alloc2_size = alloc_size - 1024;
4718 g_assert (mips_is_imm16 (-alloc_size));
4719 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4722 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4723 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4724 if (mips_is_imm16(offset))
4725 mips_sw (code, mips_ra, mips_sp, offset);
4727 g_assert_not_reached ();
4731 /* XXX - optimize this later to not save all regs if LMF constructed */
4732 pos = cfg->arch.iregs_offset - alloc2_size;
4734 if (iregs_to_save) {
4735 /* save used registers in own stack frame (at pos) */
4736 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4737 if (iregs_to_save & (1 << i)) {
4738 g_assert (pos < cfg->stack_usage - sizeof(gpointer));
4739 g_assert (mips_is_imm16(pos));
4740 MIPS_SW (code, i, mips_sp, pos);
4741 pos += SIZEOF_REGISTER;
4746 if (method->save_lmf) {
4747 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4748 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4749 g_assert (mips_is_imm16(offset));
4750 MIPS_SW (code, i, mips_sp, offset);
4756 /* Save float registers */
4757 if (fregs_to_save) {
4758 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4759 if (fregs_to_save & (1 << i)) {
4760 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4761 g_assert (mips_is_imm16(pos));
4762 mips_swc1 (code, i, mips_sp, pos);
4763 pos += sizeof (gulong);
4768 if (method->save_lmf) {
4769 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4770 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4771 g_assert (mips_is_imm16(offset));
4772 mips_swc1 (code, i, mips_sp, offset);
4777 if (cfg->frame_reg != mips_sp) {
4778 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4780 if (method->save_lmf) {
4781 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4782 g_assert (mips_is_imm16(offset));
4783 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4788 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
4789 * to the t* registers, which would be clobbered by the instrumentation calls.
4792 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4796 /* load arguments allocated to register from the stack */
4799 cinfo = calculate_sizes (sig, sig->pinvoke);
4801 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4802 ArgInfo *ainfo = &cinfo->ret;
4803 inst = cfg->vret_addr;
4804 if (inst->opcode == OP_REGVAR)
4805 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4806 else if (mips_is_imm16 (inst->inst_offset)) {
4807 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4809 mips_load_const (code, mips_at, inst->inst_offset);
4810 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4811 mips_sw (code, ainfo->reg, mips_at, 0);
4814 /* Keep this in sync with emit_load_volatile_arguments */
4815 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4816 ArgInfo *ainfo = cinfo->args + i;
4817 inst = cfg->args [pos];
4819 if (cfg->verbose_level > 2)
4820 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4821 if (inst->opcode == OP_REGVAR) {
4822 /* Argument ends up in a register */
4823 if (ainfo->regtype == RegTypeGeneral)
4824 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4825 else if (ainfo->regtype == RegTypeFP) {
4826 g_assert_not_reached();
4828 ppc_fmr (code, inst->dreg, ainfo->reg);
4831 else if (ainfo->regtype == RegTypeBase) {
4832 int offset = cfg->stack_usage + ainfo->offset;
4833 g_assert (mips_is_imm16(offset));
4834 mips_lw (code, inst->dreg, mips_sp, offset);
4836 g_assert_not_reached ();
4838 if (cfg->verbose_level > 2)
4839 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4841 /* Argument ends up on the stack */
4842 if (ainfo->regtype == RegTypeGeneral) {
4843 /* Incoming parameters should be above this frame */
4844 if (cfg->verbose_level > 2)
4845 g_print ("stack slot at %d of %d\n", inst->inst_offset, alloc_size);
4846 /* g_assert (inst->inst_offset >= alloc_size); */
4847 g_assert (mips_is_imm16 (inst->inst_offset));
4848 switch (ainfo->size) {
4850 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4853 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4857 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4860 #if (SIZEOF_REGISTER == 4)
4861 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4862 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
4863 #elif (SIZEOF_REGISTER == 8)
4864 mips_sd (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4868 g_assert_not_reached ();
4871 } else if (ainfo->regtype == RegTypeBase) {
4873 * Argument comes in on the stack, and ends up on the stack
4874 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4875 * 8 and 16 bit quantities. Shorten them in place.
4877 g_assert (mips_is_imm16 (inst->inst_offset));
4878 switch (ainfo->size) {
4880 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4881 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4884 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4885 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4892 g_assert_not_reached ();
4894 } else if (ainfo->regtype == RegTypeFP) {
4895 g_assert (mips_is_imm16 (inst->inst_offset));
4896 g_assert (mips_is_imm16 (inst->inst_offset+4));
4897 if (ainfo->size == 8) {
4898 #if _MIPS_SIM == _ABIO32
4899 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
4900 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
4901 #elif _MIPS_SIM == _ABIN32
4902 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4905 else if (ainfo->size == 4)
4906 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4908 g_assert_not_reached ();
4909 } else if (ainfo->regtype == RegTypeStructByVal) {
4911 int doffset = inst->inst_offset;
4913 g_assert (mips_is_imm16 (inst->inst_offset));
4914 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4915 /* Push the argument registers into their stack slots */
4916 for (i = 0; i < ainfo->size; ++i) {
4917 g_assert (mips_is_imm16(doffset));
4918 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
4919 doffset += SIZEOF_REGISTER;
4921 } else if (ainfo->regtype == RegTypeStructByAddr) {
4922 g_assert (mips_is_imm16 (inst->inst_offset));
4923 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4924 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4926 g_assert_not_reached ();
4931 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4932 mips_load_const (code, mips_a0, cfg->domain);
4933 mips_call (code, mips_t9, (gpointer)mono_jit_thread_attach);
4937 if (method->save_lmf) {
4938 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
4939 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
4941 if (lmf_pthread_key != -1) {
4942 g_assert_not_reached();
4944 emit_tls_access (code, mips_temp, lmf_pthread_key);
4946 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
4947 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
4948 g_assert (mips_is_imm16(offset));
4949 mips_addiu (code, mips_a0, mips_temp, offset);
4952 /* This can/will clobber the a0-a3 registers */
4953 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
4956 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4957 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
4958 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4959 /* new_lmf->previous_lmf = *lmf_addr */
4960 mips_lw (code, mips_at, mips_v0, 0);
4961 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
4962 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4963 /* *(lmf_addr) = sp + lmf_offset */
4964 g_assert (mips_is_imm16(lmf_offset));
4965 mips_addiu (code, mips_at, mips_sp, lmf_offset);
4966 mips_sw (code, mips_at, mips_v0, 0);
4968 /* save method info */
4969 mips_load_const (code, mips_at, method);
4970 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
4971 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
4972 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
4973 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
4975 /* save the current IP */
4976 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4977 mips_load_const (code, mips_at, 0x01010101);
4978 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
4982 if (mips_is_imm16 (-alloc2_size)) {
4983 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
4986 mips_load_const (code, mips_at, -alloc2_size);
4987 mips_addu (code, mips_sp, mips_sp, mips_at);
4989 if (cfg->frame_reg != mips_sp)
4990 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4991 alloc_size += alloc2_size;
4994 cfg->code_len = code - cfg->native_code;
4995 g_assert (cfg->code_len < cfg->code_size);
5010 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5013 int save_mode = SAVE_NONE;
5015 MonoMethod *method = cfg->method;
5016 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5017 int save_offset = MIPS_STACK_PARAM_OFFSET;
5019 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5021 offset = code - cfg->native_code;
5022 /* we need about 16 instructions */
5023 if (offset > (cfg->code_size - 16 * 4)) {
5024 cfg->code_size *= 2;
5025 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5026 code = cfg->native_code + offset;
5031 case MONO_TYPE_VOID:
5032 /* special case string .ctor icall */
5033 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5034 save_mode = SAVE_ONE;
5036 save_mode = SAVE_NONE;
5040 save_mode = SAVE_FP;
5042 case MONO_TYPE_VALUETYPE:
5043 save_mode = SAVE_STRUCT;
5047 #if SIZEOF_REGISTER == 4
5048 save_mode = SAVE_TWO;
5049 #elif SIZEOF_REGISTER == 8
5050 save_mode = SAVE_ONE;
5054 save_mode = SAVE_ONE;
5058 mips_addiu (code, mips_sp, mips_sp, -32);
5059 g_assert (mips_is_imm16(save_offset));
5060 switch (save_mode) {
5062 mips_sw (code, mips_v0, mips_sp, save_offset);
5063 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5064 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5065 if (enable_arguments) {
5066 MIPS_MOVE (code, mips_a1, mips_v0);
5067 MIPS_MOVE (code, mips_a2, mips_v1);
5071 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5072 if (enable_arguments) {
5073 MIPS_MOVE (code, mips_a1, mips_v0);
5077 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5078 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5079 mips_lw (code, mips_a0, mips_sp, save_offset);
5080 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5081 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5088 mips_load_const (code, mips_a0, cfg->method);
5089 mips_call (code, mips_t9, func);
5091 switch (save_mode) {
5093 mips_lw (code, mips_v0, mips_sp, save_offset);
5094 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5095 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5098 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5101 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5108 mips_addiu (code, mips_sp, mips_sp, 32);
5115 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5117 MonoMethod *method = cfg->method;
5119 int max_epilog_size = 16 + 20*4;
5120 int alloc2_size = 0;
5121 guint32 iregs_to_restore;
5123 guint32 fregs_to_restore;
5127 if (cfg->method->save_lmf)
5128 max_epilog_size += 128;
5131 if (mono_jit_trace_calls != NULL)
5132 max_epilog_size += 50;
5134 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5135 max_epilog_size += 50;
5138 pos = code - cfg->native_code;
5139 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5140 cfg->code_size *= 2;
5141 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5142 mono_jit_stats.code_reallocs++;
5146 * Keep in sync with OP_JMP
5149 code = cfg->native_code + pos;
5151 code = cfg->native_code + cfg->code_len;
5153 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5154 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5156 if (cfg->frame_reg != mips_sp) {
5157 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5159 /* If the stack frame is really large, deconstruct it in two steps */
5160 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5161 alloc2_size = cfg->stack_usage - 1024;
5162 /* partially deconstruct the stack */
5163 mips_load_const (code, mips_at, alloc2_size);
5164 mips_addu (code, mips_sp, mips_sp, mips_at);
5166 pos = cfg->arch.iregs_offset - alloc2_size;
5168 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5170 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5172 if (iregs_to_restore) {
5173 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5174 if (iregs_to_restore & (1 << i)) {
5175 g_assert (mips_is_imm16(pos));
5176 MIPS_LW (code, i, mips_sp, pos);
5177 pos += SIZEOF_REGISTER;
5184 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5186 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5187 fregs_to_restore |= (fregs_to_restore << 1);
5189 if (fregs_to_restore) {
5190 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5191 if (fregs_to_restore & (1 << i)) {
5192 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5193 g_assert (mips_is_imm16(pos));
5194 mips_lwc1 (code, i, mips_sp, pos);
5201 /* Unlink the LMF if necessary */
5202 if (method->save_lmf) {
5203 int lmf_offset = cfg->arch.lmf_offset;
5205 /* t0 = current_lmf->previous_lmf */
5206 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5207 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5209 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5210 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5211 /* (*lmf_addr) = previous_lmf */
5212 mips_sw (code, mips_temp, mips_t1, 0);
5216 /* Restore the fp */
5217 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5220 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5221 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5222 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5224 /* Restore the stack pointer */
5225 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5226 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5228 /* Caller will emit either return or tail-call sequence */
5230 cfg->code_len = code - cfg->native_code;
5232 g_assert (cfg->code_len < cfg->code_size);
5237 mono_arch_emit_epilog (MonoCompile *cfg)
5241 code = mono_arch_emit_epilog_sub (cfg, NULL);
5243 mips_jr (code, mips_ra);
5246 cfg->code_len = code - cfg->native_code;
5248 g_assert (cfg->code_len < cfg->code_size);
5251 /* remove once throw_exception_by_name is eliminated */
5254 exception_id_by_name (const char *name)
5256 if (strcmp (name, "IndexOutOfRangeException") == 0)
5257 return MONO_EXC_INDEX_OUT_OF_RANGE;
5258 if (strcmp (name, "OverflowException") == 0)
5259 return MONO_EXC_OVERFLOW;
5260 if (strcmp (name, "ArithmeticException") == 0)
5261 return MONO_EXC_ARITHMETIC;
5262 if (strcmp (name, "DivideByZeroException") == 0)
5263 return MONO_EXC_DIVIDE_BY_ZERO;
5264 if (strcmp (name, "InvalidCastException") == 0)
5265 return MONO_EXC_INVALID_CAST;
5266 if (strcmp (name, "NullReferenceException") == 0)
5267 return MONO_EXC_NULL_REF;
5268 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5269 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5270 if (strcmp (name, "ArgumentException") == 0)
5271 return MONO_EXC_ARGUMENT;
5272 g_error ("Unknown intrinsic exception %s\n", name);
5278 mono_arch_emit_exceptions (MonoCompile *cfg)
5281 MonoJumpInfo *patch_info;
5284 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5285 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5286 int max_epilog_size = 50;
5288 /* count the number of exception infos */
5291 * make sure we have enough space for exceptions
5292 * 24 is the simulated call to throw_exception_by_name
5294 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5296 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5297 i = exception_id_by_name (patch_info->data.target);
5298 g_assert (i < MONO_EXC_INTRINS_NUM);
5299 if (!exc_throw_found [i]) {
5300 max_epilog_size += 12;
5301 exc_throw_found [i] = TRUE;
5307 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5308 cfg->code_size *= 2;
5309 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5310 mono_jit_stats.code_reallocs++;
5313 code = cfg->native_code + cfg->code_len;
5315 /* add code to raise exceptions */
5316 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5317 switch (patch_info->type) {
5318 case MONO_PATCH_INFO_EXC: {
5320 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5322 i = exception_id_by_name (patch_info->data.target);
5323 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5324 if (!exc_throw_pos [i]) {
5327 exc_throw_pos [i] = code;
5328 //g_print ("exc: writing stub at %p\n", code);
5329 mips_load_const (code, mips_a0, patch_info->data.target);
5330 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5331 mips_load_const (code, mips_t9, addr);
5332 mips_jr (code, mips_t9);
5335 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5337 /* Turn into a Relative patch, pointing at code stub */
5338 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5339 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5341 g_assert_not_reached();
5351 cfg->code_len = code - cfg->native_code;
5353 g_assert (cfg->code_len < cfg->code_size);
5358 * Thread local storage support
5361 setup_tls_access (void)
5364 //guint32 *ins, *code;
5366 if (tls_mode == TLS_MODE_FAILED)
5369 if (g_getenv ("MONO_NO_TLS")) {
5370 tls_mode = TLS_MODE_FAILED;
5374 if (tls_mode == TLS_MODE_DETECT) {
5376 tls_mode = TLS_MODE_FAILED;
5380 ins = (guint32*)pthread_getspecific;
5381 /* uncond branch to the real method */
5382 if ((*ins >> 26) == 18) {
5384 val = (*ins & ~3) << 6;
5388 ins = (guint32*)val;
5390 ins = (guint32*) ((char*)ins + val);
5393 code = &cmplwi_1023;
5394 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5396 ppc_li (code, ppc_r4, 0x48);
5399 if (*ins == cmplwi_1023) {
5400 int found_lwz_284 = 0;
5401 for (ptk = 0; ptk < 20; ++ptk) {
5403 if (!*ins || *ins == blr_ins)
5405 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5410 if (!found_lwz_284) {
5411 tls_mode = TLS_MODE_FAILED;
5414 tls_mode = TLS_MODE_LTHREADS;
5415 } else if (*ins == li_0x48) {
5417 /* uncond branch to the real method */
5418 if ((*ins >> 26) == 18) {
5420 val = (*ins & ~3) << 6;
5424 ins = (guint32*)val;
5426 ins = (guint32*) ((char*)ins + val);
5429 ppc_li (code, ppc_r0, 0x7FF2);
5430 if (ins [1] == val) {
5431 /* Darwin on G4, implement */
5432 tls_mode = TLS_MODE_FAILED;
5436 ppc_mfspr (code, ppc_r3, 104);
5437 if (ins [1] != val) {
5438 tls_mode = TLS_MODE_FAILED;
5441 tls_mode = TLS_MODE_DARWIN_G5;
5444 tls_mode = TLS_MODE_FAILED;
5448 tls_mode = TLS_MODE_FAILED;
5453 if (monodomain_key == -1) {
5454 ptk = mono_domain_get_tls_key ();
5456 ptk = mono_pthread_key_for_tls (ptk);
5458 monodomain_key = ptk;
5462 if (lmf_pthread_key == -1) {
5463 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5465 /*g_print ("MonoLMF at: %d\n", ptk);*/
5466 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5467 init_tls_failed = 1;
5470 lmf_pthread_key = ptk;
5473 if (monothread_key == -1) {
5474 ptk = mono_thread_get_tls_key ();
5476 ptk = mono_pthread_key_for_tls (ptk);
5478 monothread_key = ptk;
5479 /*g_print ("thread inited: %d\n", ptk);*/
5482 /*g_print ("thread not inited yet %d\n", ptk);*/
5488 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5490 setup_tls_access ();
5494 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5499 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5501 int this_dreg = mips_a0;
5504 this_dreg = mips_a1;
5506 /* add the this argument */
5507 if (this_reg != -1) {
5509 MONO_INST_NEW (cfg, this, OP_MOVE);
5510 this->type = this_type;
5511 this->sreg1 = this_reg;
5512 this->dreg = mono_alloc_ireg (cfg);
5513 mono_bblock_add_inst (cfg->cbb, this);
5514 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5519 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5520 vtarg->type = STACK_MP;
5521 vtarg->sreg1 = vt_reg;
5522 vtarg->dreg = mono_alloc_ireg (cfg);
5523 mono_bblock_add_inst (cfg->cbb, vtarg);
5524 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5529 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5531 MonoInst *ins = NULL;
5537 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5543 mono_arch_print_tree (MonoInst *tree, int arity)
5548 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5552 setup_tls_access ();
5553 if (monodomain_key == -1)
5556 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5557 ins->inst_offset = monodomain_key;
5562 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5564 /* FIXME: implement */
5565 g_assert_not_reached ();
5568 #ifdef MONO_ARCH_HAVE_IMT
5570 #define ENABLE_WRONG_METHOD_CHECK 0
5572 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5573 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5575 #define LOADSTORE_SIZE 4
5576 #define JUMP_IMM_SIZE 16
5577 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5578 #define LOAD_CONST_SIZE 8
5579 #define JUMP_JR_SIZE 8
5582 * LOCKING: called with the domain lock held
5585 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5586 gpointer fail_tramp)
5590 guint8 *code, *start, *patch;
5592 for (i = 0; i < count; ++i) {
5593 MonoIMTCheckItem *item = imt_entries [i];
5595 item->chunk_size += LOAD_CONST_SIZE;
5596 if (item->is_equals) {
5597 if (item->check_target_idx) {
5598 item->chunk_size += BR_SIZE + LOAD_CONST_SIZE + JUMP_JR_SIZE;
5601 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE * 2;
5602 if (!item->has_target_code)
5603 item->chunk_size += LOADSTORE_SIZE;
5605 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5606 #if ENABLE_WRONG_METHOD_CHECK
5607 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5612 item->chunk_size += BR_SIZE;
5613 imt_entries [item->check_target_idx]->compare_done = TRUE;
5615 size += item->chunk_size;
5617 /* the initial load of the vtable address */
5618 size += MIPS_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5620 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5622 code = mono_domain_code_reserve (domain, size);
5628 * We need to save and restore r11 because it might be
5629 * used by the caller as the vtable register, so
5630 * clobbering it will trip up the magic trampoline.
5632 * FIXME: Get rid of this by making sure that r11 is
5633 * not used as the vtable register in interface calls.
5635 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5636 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5638 /* t7 points to the vtable */
5639 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5641 for (i = 0; i < count; ++i) {
5642 MonoIMTCheckItem *item = imt_entries [i];
5644 item->code_target = code;
5645 mips_load_const (code, mips_temp, (gsize)item->key);
5646 if (item->is_equals) {
5647 if (item->check_target_idx) {
5648 item->jmp_code = code;
5649 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5651 if (item->has_target_code) {
5652 mips_load_const (code, mips_t9,
5653 item->value.target_code);
5656 mips_lw (code, mips_t9, mips_t7,
5657 (sizeof (gpointer) * item->value.vtable_slot));
5659 mips_jr (code, mips_t9);
5664 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5666 if (item->has_target_code) {
5667 mips_load_const (code, mips_t9,
5668 item->value.target_code);
5671 mips_load_const (code, mips_at,
5672 & (vtable->vtable [item->value.vtable_slot]));
5673 mips_lw (code, mips_t9, mips_at, 0);
5675 mips_jr (code, mips_t9);
5677 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5678 mips_load_const (code, mips_at, fail_tramp);
5679 mips_lw (code, mips_t9, mips_at, 0);
5680 mips_jr (code, mips_t9);
5683 /* enable the commented code to assert on wrong method */
5684 #if ENABLE_WRONG_METHOD_CHECK
5685 ppc_load (code, ppc_r0, (guint32)item->key);
5686 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5688 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5690 mips_lw (code, mips_t9, mips_t7,
5691 (sizeof (gpointer) * item->value.vtable_slot));
5692 mips_jr (code, mips_t9);
5695 #if ENABLE_WRONG_METHOD_CHECK
5696 ppc_patch (patch, code);
5702 mips_load_const (code, mips_temp, (gulong)item->key);
5703 mips_slt (code, mips_temp, mips_temp, MONO_ARCH_IMT_REG);
5705 item->jmp_code = code;
5706 mips_bne (code, mips_temp, mips_zero, 0);
5710 /* patch the branches to get to the target items */
5711 for (i = 0; i < count; ++i) {
5712 MonoIMTCheckItem *item = imt_entries [i];
5713 if (item->jmp_code && item->check_target_idx) {
5714 mips_patch ((guint32 *)item->jmp_code,
5715 (guint32)imt_entries [item->check_target_idx]->code_target);
5720 mono_stats.imt_thunks_size += code - start;
5721 g_assert (code - start <= size);
5722 mono_arch_flush_icache (start, size);
5727 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5729 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5734 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5737 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];