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 "mini-mips.h"
26 #warning "The mips backend is still being ported to the linear IR."
28 #define SAVE_FP_REGS 0
29 #define SAVE_ALL_REGS 0
30 #define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
31 #define LONG_BRANCH 1 /* needed for yyparse in mcs */
34 #define ALWAYS_USE_FP 1
35 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
44 /* This mutex protects architecture specific caches */
45 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
46 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
47 static CRITICAL_SECTION mini_arch_mutex;
49 int mono_exc_esp_offset = 0;
50 static int tls_mode = TLS_MODE_DETECT;
51 static int lmf_pthread_key = -1;
52 static int monothread_key = -1;
53 static int monodomain_key = -1;
56 #define DEBUG(a) if (cfg->verbose_level > 1) a
62 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
64 code = mips_emit_exc_by_name (code, exc_name); \
65 cfg->bb_exit->max_offset += 16; \
69 #define emit_linuxthreads_tls(code,dreg,key) do {\
71 off1 = offsets_from_pthread_key ((key), &off2); \
72 g_assert_not_reached (); \
73 ppc_lwz ((code), (dreg), off1, ppc_r2); \
74 ppc_lwz ((code), (dreg), off2, (dreg)); \
78 #define emit_tls_access(code,dreg,key) do { \
80 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
81 default: g_assert_not_reached (); \
85 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
87 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
88 inst->type = STACK_R8; \
90 inst->inst_p0 = (void*)(addr); \
91 mono_bblock_add_inst (cfg->cbb, inst); \
94 typedef struct InstList InstList;
112 guint16 vtsize; /* in param area */
114 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
115 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
132 void patch_lui_addiu(guint32 *ip, guint32 val);
133 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
136 mono_arch_flush_icache (guint8 *code, gint size)
138 /* Linux/MIPS specific */
139 cacheflush (code, size, BCACHE);
143 mono_arch_flush_register_windows (void)
148 mono_arch_is_inst_imm (gint64 imm)
154 mips_emit_exc_by_name(guint8 *code, const char *name)
158 mips_load_const (code, mips_a0, name);
159 addr = (guint32) mono_arch_get_throw_exception_by_name ();
160 mips_load_const (code, mips_t9, addr);
161 mips_jalr (code, mips_t9, mips_ra);
169 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
175 /* Invert test and emit branch around jump */
178 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
182 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
186 mips_bltz (code, ins->sreg1, br_offset);
190 mips_blez (code, ins->sreg1, br_offset);
194 mips_bgtz (code, ins->sreg1, br_offset);
198 mips_bgez (code, ins->sreg1, br_offset);
202 g_assert_not_reached ();
204 if (ins->flags & MONO_INST_BRLABEL)
205 mono_add_patch_info (cfg, code - cfg->native_code,
206 MONO_PATCH_INFO_LABEL, ins->inst_i0);
208 mono_add_patch_info (cfg, code - cfg->native_code,
209 MONO_PATCH_INFO_BB, ins->inst_true_bb);
210 mips_lui (code, mips_at, mips_zero, 0);
211 mips_addiu (code, mips_at, mips_at, 0);
212 mips_jr (code, mips_at);
215 if (ins->flags & MONO_INST_BRLABEL)
216 mono_add_patch_info (cfg, code - cfg->native_code,
217 MONO_PATCH_INFO_LABEL, ins->inst_i0);
219 mono_add_patch_info (cfg, code - cfg->native_code,
220 MONO_PATCH_INFO_BB, ins->inst_true_bb);
223 mips_beq (code, ins->sreg1, ins->sreg2, 0);
227 mips_bne (code, ins->sreg1, ins->sreg2, 0);
231 mips_bgez (code, ins->sreg1, 0);
235 mips_bgtz (code, ins->sreg1, 0);
239 mips_blez (code, ins->sreg1, 0);
243 mips_bltz (code, ins->sreg1, 0);
247 g_assert_not_reached ();
253 /* XXX - big-endian dependent? */
255 patch_lui_addiu(guint32 *ip, guint32 val)
257 guint16 *__lui_addiu = (guint16*)(void *)(ip);
260 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
261 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
264 if (((guint32)(val)) & (1 << 15))
265 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
267 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
268 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
269 mono_arch_flush_icache ((guint8 *)ip, 8);
274 mips_patch (guint32 *code, guint32 target)
277 guint32 op = ins >> 26;
278 guint32 diff, offset;
280 g_assert (trap_target != target);
281 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
283 case 0x00: /* jr ra */
284 if (ins == 0x3e00008)
286 g_assert_not_reached ();
290 g_assert (!(target & 0x03));
291 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
292 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
294 mono_arch_flush_icache ((guint8 *)code, 4);
296 case 0x01: /* BLTZ */
299 case 0x06: /* BLEZ */
300 case 0x07: /* BGTZ */
301 case 0x11: /* bc1t */
302 diff = target - (guint32)(code + 1);
303 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
304 g_assert (!(diff & 0x03));
305 offset = ((gint32)diff) >> 2;
306 g_assert (((int)offset) == ((int)(short)offset));
307 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
309 mono_arch_flush_icache ((guint8 *)code, 4);
311 case 0x0f: /* LUI / ADDIU pair */
312 patch_lui_addiu (code, target);
313 mono_arch_flush_icache ((guint8 *)code, 8);
317 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
318 g_assert_not_reached ();
323 offsets_from_pthread_key (guint32 key, int *offset2)
327 *offset2 = idx2 * sizeof (gpointer);
328 return 284 + idx1 * sizeof (gpointer);
332 mono_arch_regname (int reg) {
333 static const char * rnames[] = {
334 "zero", "at", "v0", "v1",
335 "a0", "a1", "a2", "a3",
336 "t0", "t1", "t2", "t3",
337 "t4", "t5", "t6", "t7",
338 "s0", "s1", "s2", "s3",
339 "s4", "s5", "s6", "s7",
340 "t8", "t9", "k0", "k1",
341 "gp", "sp", "fp", "ra"
343 if (reg >= 0 && reg < 32)
349 mono_arch_fregname (int reg) {
350 static const char * rnames[] = {
351 "f0", "f1", "f2", "f3",
352 "f4", "f5", "f6", "f7",
353 "f8", "f9", "f10", "f11",
354 "f12", "f13", "f14", "f15",
355 "f16", "f17", "f18", "f19",
356 "f20", "f21", "f22", "f23",
357 "f24", "f25", "f26", "f27",
358 "f28", "f29", "f30", "f31"
360 if (reg >= 0 && reg < 32)
365 /* this function overwrites at */
367 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
369 /* XXX write a loop, not an unrolled loop */
371 mips_lw (code, mips_at, sreg, soffset);
372 mips_sw (code, mips_at, dreg, doffset);
381 * mono_arch_get_argument_info:
382 * @csig: a method signature
383 * @param_count: the number of parameters to consider
384 * @arg_info: an array to store the result infos
386 * Gathers information on parameters such as size, alignment and
387 * padding. arg_info should be large enought to hold param_count + 1 entries.
389 * Returns the size of the activation frame.
392 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
394 int k, frame_size = 0;
395 guint32 size, align, pad;
398 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
399 frame_size += sizeof (gpointer);
403 arg_info [0].offset = offset;
406 frame_size += sizeof (gpointer);
410 arg_info [0].size = frame_size;
412 for (k = 0; k < param_count; k++) {
413 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
415 /* ignore alignment for now */
418 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
419 arg_info [k].pad = pad;
421 arg_info [k + 1].pad = 0;
422 arg_info [k + 1].size = size;
424 arg_info [k + 1].offset = offset;
428 align = MONO_ARCH_FRAME_ALIGNMENT;
429 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
430 arg_info [k].pad = pad;
437 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
439 /* FIXME: handle returning a struct */
440 if (MONO_TYPE_ISSTRUCT (sig->ret))
441 return (gpointer)regs [mips_a1];
442 return (gpointer)regs [mips_a0];
446 * Initialize the cpu to execute managed code.
449 mono_arch_cpu_init (void)
454 * Initialize architecture specific code.
457 mono_arch_init (void)
459 InitializeCriticalSection (&mini_arch_mutex);
463 * Cleanup architecture specific code.
466 mono_arch_cleanup (void)
468 DeleteCriticalSection (&mini_arch_mutex);
472 * This function returns the optimizations supported on this cpu.
475 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
479 /* no mips-specific optimizations yet */
485 is_regsize_var (MonoType *t) {
488 t = mono_type_get_underlying_type (t);
495 case MONO_TYPE_FNPTR:
497 case MONO_TYPE_OBJECT:
498 case MONO_TYPE_STRING:
499 case MONO_TYPE_CLASS:
500 case MONO_TYPE_SZARRAY:
501 case MONO_TYPE_ARRAY:
503 case MONO_TYPE_GENERICINST:
504 if (!mono_type_generic_inst_is_valuetype (t))
507 case MONO_TYPE_VALUETYPE:
514 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
519 for (i = 0; i < cfg->num_varinfo; i++) {
520 MonoInst *ins = cfg->varinfo [i];
521 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
524 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
527 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
530 /* we can only allocate 32 bit values */
531 if (is_regsize_var (ins->inst_vtype)) {
532 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
533 g_assert (i == vmv->idx);
534 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
542 mono_arch_get_global_int_regs (MonoCompile *cfg)
546 regs = g_list_prepend (regs, (gpointer)mips_s0);
547 regs = g_list_prepend (regs, (gpointer)mips_s1);
548 regs = g_list_prepend (regs, (gpointer)mips_s2);
549 regs = g_list_prepend (regs, (gpointer)mips_s3);
550 regs = g_list_prepend (regs, (gpointer)mips_s4);
551 //regs = g_list_prepend (regs, (gpointer)mips_s5);
552 regs = g_list_prepend (regs, (gpointer)mips_s6);
553 regs = g_list_prepend (regs, (gpointer)mips_s7);
559 * mono_arch_regalloc_cost:
561 * Return the cost, in number of memory references, of the action of
562 * allocating the variable VMV into a register during global register
566 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
573 args_onto_stack (CallInfo *info)
575 g_assert(!info->on_stack);
576 g_assert(info->stack_size <= MIPS_STACK_PARAM_OFFSET);
577 info->on_stack = TRUE;
578 info->stack_size = MIPS_STACK_PARAM_OFFSET;
582 * O32 calling convention version
586 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
587 /* First, see if we need to drop onto the stack */
588 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
589 args_onto_stack (info);
591 /* Now, place the argument */
592 if (info->on_stack) {
593 ainfo->regtype = RegTypeBase;
594 ainfo->reg = mips_sp; /* in the caller */
595 ainfo->offset = info->stack_size;
598 ainfo->regtype = RegTypeGeneral;
599 ainfo->reg = info->gr;
601 info->gr_passed = TRUE;
603 info->stack_size += 4;
607 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
608 /* First, see if we need to drop onto the stack */
609 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
610 args_onto_stack (info);
612 /* Now, place the argument */
613 if (info->on_stack) {
614 g_assert(info->stack_size % 4 == 0);
615 info->stack_size += (info->stack_size % 8);
617 ainfo->regtype = RegTypeBase;
618 ainfo->reg = mips_sp; /* in the caller */
619 ainfo->offset = info->stack_size;
622 // info->gr must be a0 or a2
623 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
624 g_assert(info->gr <= MIPS_LAST_ARG_REG);
626 ainfo->regtype = RegTypeGeneral;
627 ainfo->reg = info->gr;
629 info->gr_passed = TRUE;
631 info->stack_size += 8;
635 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
636 /* First, see if we need to drop onto the stack */
637 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
638 args_onto_stack (info);
640 /* Now, place the argument */
641 if (info->on_stack) {
642 ainfo->regtype = RegTypeBase;
643 ainfo->reg = mips_sp; /* in the caller */
644 ainfo->offset = info->stack_size;
647 /* Only use FP regs for args if no int args passed yet */
648 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
649 ainfo->regtype = RegTypeFP;
650 ainfo->reg = info->fr;
651 /* Even though it's a single-precision float, it takes up two FP regs */
653 /* FP and GP slots do not overlap */
657 /* Passing single-precision float arg in a GP register
658 * such as: func (0, 1.0, 2, 3);
659 * In this case, only one 'gr' register is consumed.
661 ainfo->regtype = RegTypeGeneral;
662 ainfo->reg = info->gr;
665 info->gr_passed = TRUE;
668 info->stack_size += 4;
672 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
673 /* First, see if we need to drop onto the stack */
674 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
675 args_onto_stack (info);
677 /* Now, place the argument */
678 if (info->on_stack) {
679 g_assert(info->stack_size % 4 == 0);
680 info->stack_size += (info->stack_size % 8);
682 ainfo->regtype = RegTypeBase;
683 ainfo->reg = mips_sp; /* in the caller */
684 ainfo->offset = info->stack_size;
687 /* Only use FP regs for args if no int args passed yet */
688 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
689 ainfo->regtype = RegTypeFP;
690 ainfo->reg = info->fr;
692 /* FP and GP slots do not overlap */
696 // info->gr must be a0 or a2
697 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
698 g_assert(info->gr <= MIPS_LAST_ARG_REG);
700 ainfo->regtype = RegTypeGeneral;
701 ainfo->reg = info->gr;
703 info->gr_passed = TRUE;
706 info->stack_size += 8;
710 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
713 int n = sig->hasthis + sig->param_count;
715 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
717 cinfo->fr = MIPS_FIRST_FPARG_REG;
718 cinfo->gr = MIPS_FIRST_ARG_REG;
719 cinfo->stack_size = 0;
721 DEBUG(printf("calculate_sizes\n"));
723 /* handle returning a struct */
724 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
725 cinfo->struct_ret = cinfo->gr;
726 add_int32_arg (cinfo, &cinfo->ret);
731 add_int32_arg (cinfo, cinfo->args + n);
734 DEBUG(printf("params: %d\n", sig->param_count));
735 for (i = 0; i < sig->param_count; ++i) {
736 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
737 /* Prevent implicit arguments and sig_cookie from
738 being passed in registers */
739 args_onto_stack (cinfo);
740 /* Emit the signature cookie just before the implicit arguments */
741 add_int32_arg (cinfo, &cinfo->sig_cookie);
743 DEBUG(printf("param %d: ", i));
744 if (sig->params [i]->byref) {
745 DEBUG(printf("byref\n"));
746 add_int32_arg (cinfo, &cinfo->args[n]);
750 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
751 switch (simpletype) {
752 case MONO_TYPE_BOOLEAN:
755 DEBUG(printf("1 byte\n"));
756 cinfo->args [n].size = 1;
757 add_int32_arg (cinfo, &cinfo->args[n]);
763 DEBUG(printf("2 bytes\n"));
764 cinfo->args [n].size = 2;
765 add_int32_arg (cinfo, &cinfo->args[n]);
770 DEBUG(printf("4 bytes\n"));
771 cinfo->args [n].size = 4;
772 add_int32_arg (cinfo, &cinfo->args[n]);
778 case MONO_TYPE_FNPTR:
779 case MONO_TYPE_CLASS:
780 case MONO_TYPE_OBJECT:
781 case MONO_TYPE_STRING:
782 case MONO_TYPE_SZARRAY:
783 case MONO_TYPE_ARRAY:
784 cinfo->args [n].size = sizeof (gpointer);
785 add_int32_arg (cinfo, &cinfo->args[n]);
788 case MONO_TYPE_GENERICINST:
789 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
790 cinfo->args [n].size = sizeof (gpointer);
791 add_int32_arg (cinfo, &cinfo->args[n]);
796 case MONO_TYPE_VALUETYPE: {
799 int has_offset = FALSE;
801 gint size, alignment;
804 klass = mono_class_from_mono_type (sig->params [i]);
806 size = mono_class_native_size (klass, NULL);
808 size = mono_class_value_size (klass, NULL);
809 alignment = mono_class_min_align (klass);
810 #if MIPS_PASS_STRUCTS_BY_VALUE
811 /* Need to do alignment if struct contains long or double */
813 if (cinfo->stack_size & (alignment - 1)) {
814 add_int32_arg (cinfo, &dummy_arg);
816 g_assert (!(cinfo->stack_size & (alignment - 1)));
820 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
821 mono_class_native_size (sig->params [i]->data.klass, NULL),
822 cinfo->stack_size, alignment);
824 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
825 g_assert(cinfo->args [n].size == 0);
826 g_assert(cinfo->args [n].vtsize == 0);
827 for (j = 0; j < nwords; ++j) {
829 add_int32_arg (cinfo, &cinfo->args [n]);
833 add_int32_arg (cinfo, &dummy_arg);
834 if (!has_offset && cinfo->on_stack) {
835 cinfo->args [n].offset = dummy_arg.offset;
840 cinfo->args [n].vtsize += 1;
842 cinfo->args [n].size += 1;
844 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
845 cinfo->args [n].regtype = RegTypeStructByVal;
847 add_int32_arg (cinfo, &cinfo->args[n]);
848 cinfo->args [n].regtype = RegTypeStructByAddr;
853 case MONO_TYPE_TYPEDBYREF: {
854 /* keep in sync or merge with the valuetype case */
855 #if MIPS_PASS_STRUCTS_BY_VALUE
857 int size = sizeof (MonoTypedRef);
858 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
859 cinfo->args [n].regtype = RegTypeStructByVal;
860 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
861 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
862 int n_in_regs = rest >= nwords? nwords: rest;
863 cinfo->args [n].size = n_in_regs;
864 cinfo->args [n].vtsize = nwords - n_in_regs;
865 cinfo->args [n].reg = cinfo->gr;
866 cinfo->gr += n_in_regs;
867 cinfo->gr_passed = TRUE;
869 cinfo->args [n].size = 0;
870 cinfo->args [n].vtsize = nwords;
872 if (cinfo->args [n].vtsize > 0) {
873 if (!cinfo->on_stack)
874 args_onto_stack (cinfo);
875 g_assert(cinfo->on_stack);
876 cinfo->args [n].offset = cinfo->stack_size;
877 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
878 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
882 add_int32_arg (cinfo, &cinfo->args[n]);
883 cinfo->args [n].regtype = RegTypeStructByAddr;
890 DEBUG(printf("8 bytes\n"));
891 cinfo->args [n].size = 8;
892 add_int64_arg (cinfo, &cinfo->args[n]);
896 DEBUG(printf("R4\n"));
897 cinfo->args [n].size = 4;
898 add_float32_arg (cinfo, &cinfo->args[n]);
902 DEBUG(printf("R8\n"));
903 cinfo->args [n].size = 8;
904 add_float64_arg (cinfo, &cinfo->args[n]);
908 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
913 simpletype = mono_type_get_underlying_type (sig->ret)->type;
914 switch (simpletype) {
915 case MONO_TYPE_BOOLEAN:
926 case MONO_TYPE_FNPTR:
927 case MONO_TYPE_CLASS:
928 case MONO_TYPE_OBJECT:
929 case MONO_TYPE_SZARRAY:
930 case MONO_TYPE_ARRAY:
931 case MONO_TYPE_STRING:
932 cinfo->ret.reg = mips_v0;
936 cinfo->ret.reg = mips_v0;
940 cinfo->ret.reg = mips_f0;
941 cinfo->ret.regtype = RegTypeFP;
943 case MONO_TYPE_GENERICINST:
944 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
945 cinfo->ret.reg = mips_v0;
949 case MONO_TYPE_VALUETYPE:
951 case MONO_TYPE_TYPEDBYREF:
955 g_error ("Can't handle as return value 0x%x", sig->ret->type);
959 /* align stack size to 16 */
960 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
962 cinfo->stack_usage = cinfo->stack_size;
968 * Set var information according to the calling convention. mips version.
969 * The locals var stuff should most likely be split in another method.
972 mono_arch_allocate_vars (MonoCompile *cfg)
974 MonoMethodSignature *sig;
975 MonoMethodHeader *header;
977 int i, offset, size, align, curinst;
978 int frame_reg = mips_sp;
979 guint32 iregs_to_save = 0;
980 guint32 fregs_to_restore;
982 /* spill down, we'll fix it in a separate pass */
983 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
985 /* allow room for the vararg method args: void* and long/double */
986 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
987 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
989 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
990 * call convs needs to be handled this way.
992 if (cfg->flags & MONO_CFG_HAS_VARARGS)
993 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
995 /* gtk-sharp and other broken code will dllimport vararg functions even with
996 * non-varargs signatures. Since there is little hope people will get this right
997 * we assume they won't.
999 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1000 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1002 /* a0-a3 always present */
1003 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1005 header = mono_method_get_header (cfg->method);
1007 sig = mono_method_signature (cfg->method);
1010 * We use the frame register also for any method that has
1011 * exception clauses. This way, when the handlers are called,
1012 * the code will reference local variables using the frame reg instead of
1013 * the stack pointer: if we had to restore the stack pointer, we'd
1014 * corrupt the method frames that are already on the stack (since
1015 * filters get called before stack unwinding happens) when the filter
1016 * code would call any method (this also applies to finally etc.).
1019 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
1020 frame_reg = mips_fp;
1021 cfg->frame_reg = frame_reg;
1022 if (frame_reg != mips_sp) {
1023 cfg->used_int_regs |= 1 << frame_reg;
1028 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1029 /* FIXME: handle long and FP values */
1030 switch (mono_type_get_underlying_type (sig->ret)->type) {
1031 case MONO_TYPE_VOID:
1034 cfg->ret->opcode = OP_REGVAR;
1035 cfg->ret->inst_c0 = mips_v0;
1039 /* Space for outgoing parameters, including a0-a3 */
1040 offset += cfg->param_area;
1042 /* allow room to save the return value (if it's a struct) */
1043 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1046 if (sig->call_convention == MONO_CALL_VARARG) {
1047 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1050 /* Now handle the local variables */
1052 curinst = cfg->locals_start;
1053 for (i = curinst; i < cfg->num_varinfo; ++i) {
1054 inst = cfg->varinfo [i];
1055 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1058 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1059 * pinvoke wrappers when they call functions returning structure
1061 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1062 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1064 size = mono_type_size (inst->inst_vtype, &align);
1066 offset += align - 1;
1067 offset &= ~(align - 1);
1068 inst->inst_offset = offset;
1069 inst->opcode = OP_REGOFFSET;
1070 inst->inst_basereg = frame_reg;
1072 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1075 /* Space for LMF (if needed) */
1077 if (cfg->method->save_lmf) {
1078 /* align the offset to 16 bytes */
1079 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1080 cfg->arch.lmf_offset = offset;
1081 offset += sizeof (MonoLMF);
1085 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1086 * args or return vals. Extra stack space avoids this in a lot of cases.
1088 offset += EXTRA_STACK_SPACE;
1090 /* Space for saved registers */
1091 cfg->arch.iregs_offset = offset;
1093 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1095 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1097 if (iregs_to_save) {
1098 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1099 if (iregs_to_save & (1 << i)) {
1100 offset += sizeof (gulong);
1105 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1106 * args or return vals. Extra stack space avoids this in a lot of cases.
1108 offset += EXTRA_STACK_SPACE;
1110 /* saved float registers */
1112 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1113 if (fregs_to_restore) {
1114 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1115 if (fregs_to_restore & (1 << i)) {
1116 offset += sizeof (double);
1122 /* Now add space for saving the ra */
1126 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1127 cfg->stack_offset = offset;
1128 cfg->arch.local_alloc_offset = cfg->stack_offset;
1131 * Now allocate stack slots for the int arg regs (a0 - a3)
1132 * On MIPS o32, these are just above the incoming stack pointer
1133 * Even if the arg has been assigned to a regvar, it gets a stack slot
1136 /* Return struct-by-value results in a hidden first argument */
1137 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1138 cfg->vret_addr->opcode = OP_REGOFFSET;
1139 cfg->vret_addr->inst_c0 = mips_a0;
1140 cfg->vret_addr->inst_offset = offset;
1141 cfg->vret_addr->inst_basereg = frame_reg;
1145 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1146 inst = cfg->args [i];
1147 if (inst->opcode != OP_REGVAR) {
1150 if (sig->hasthis && (i == 0))
1151 arg_type = &mono_defaults.object_class->byval_arg;
1153 arg_type = sig->params [i - sig->hasthis];
1155 inst->opcode = OP_REGOFFSET;
1156 size = mono_type_size (arg_type, &align);
1162 inst->inst_basereg = frame_reg;
1163 offset = (offset + align - 1) & ~(align - 1);
1164 inst->inst_offset = offset;
1166 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1167 cfg->sig_cookie += size;
1168 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1171 /* Even a0-a3 get stack slots */
1172 size = sizeof (gpointer);
1173 align = sizeof (gpointer);
1174 inst->inst_basereg = frame_reg;
1175 offset = (offset + align - 1) & ~(align - 1);
1176 inst->inst_offset = offset;
1178 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1179 cfg->sig_cookie += size;
1180 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1186 mono_arch_create_vars (MonoCompile *cfg)
1188 MonoMethodSignature *sig;
1190 sig = mono_method_signature (cfg->method);
1192 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1193 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1194 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1195 printf ("vret_addr = ");
1196 mono_print_ins (cfg->vret_addr);
1201 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1202 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1206 * take the arguments and generate the arch-specific
1207 * instructions to properly call the function in call.
1208 * This includes pushing, moving arguments to the right register
1210 * Issue: who does the spilling if needed, and when?
1213 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1215 int sig_reg = mono_alloc_ireg (cfg);
1217 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1218 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1219 mips_sp, cinfo->sig_cookie.offset, sig_reg);
1223 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1226 MonoMethodSignature *sig;
1231 sig = call->signature;
1232 n = sig->param_count + sig->hasthis;
1234 cinfo = calculate_sizes (sig, sig->pinvoke);
1235 if (cinfo->struct_ret)
1236 call->used_iregs |= 1 << cinfo->struct_ret;
1238 for (i = 0; i < n; ++i) {
1239 ArgInfo *ainfo = cinfo->args + i;
1242 if (i >= sig->hasthis)
1243 t = sig->params [i - sig->hasthis];
1245 t = &mono_defaults.int_class->byval_arg;
1246 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1248 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1249 emit_sig_cookie (cfg, call, cinfo);
1250 if (is_virtual && i == 0) {
1251 /* the argument will be attached to the call instrucion */
1252 in = call->args [i];
1253 call->used_iregs |= 1 << ainfo->reg;
1256 in = call->args [i];
1257 if (ainfo->regtype == RegTypeGeneral) {
1258 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1259 MONO_INST_NEW (cfg, ins, OP_MOVE);
1260 ins->dreg = mono_alloc_ireg (cfg);
1261 ins->sreg1 = in->dreg + 1;
1262 MONO_ADD_INS (cfg->cbb, ins);
1263 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1265 MONO_INST_NEW (cfg, ins, OP_MOVE);
1266 ins->dreg = mono_alloc_ireg (cfg);
1267 ins->sreg1 = in->dreg + 2;
1268 MONO_ADD_INS (cfg->cbb, ins);
1269 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1270 } else if (!t->byref && (t->type == MONO_TYPE_R4)) {
1271 /* trying to load float value into int registers */
1272 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1273 ins->dreg = mono_alloc_ireg (cfg);
1274 ins->sreg1 = in->dreg;
1275 MONO_ADD_INS (cfg->cbb, ins);
1276 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1277 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1278 /* trying to load float value into int registers */
1279 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1280 ins->dreg = mono_alloc_ireg (cfg);
1281 ins->sreg1 = in->dreg;
1282 MONO_ADD_INS (cfg->cbb, ins);
1283 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1285 MONO_INST_NEW (cfg, ins, OP_MOVE);
1286 ins->dreg = mono_alloc_ireg (cfg);
1287 ins->sreg1 = in->dreg;
1288 MONO_ADD_INS (cfg->cbb, ins);
1289 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1291 } else if (ainfo->regtype == RegTypeStructByAddr) {
1292 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1293 ins->opcode = OP_OUTARG_VT;
1294 ins->sreg1 = in->dreg;
1295 ins->klass = in->klass;
1296 ins->inst_p0 = call;
1297 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1298 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1299 MONO_ADD_INS (cfg->cbb, ins);
1300 } else if (ainfo->regtype == RegTypeStructByVal) {
1301 /* this is further handled in mono_arch_emit_outarg_vt () */
1302 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1303 ins->opcode = OP_OUTARG_VT;
1304 ins->sreg1 = in->dreg;
1305 ins->klass = in->klass;
1306 ins->inst_p0 = call;
1307 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1308 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1309 MONO_ADD_INS (cfg->cbb, ins);
1310 } else if (ainfo->regtype == RegTypeBase) {
1311 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1312 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1313 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1314 if (t->type == MONO_TYPE_R8)
1315 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1317 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1319 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1321 } else if (ainfo->regtype == RegTypeFP) {
1322 if (t->type == MONO_TYPE_VALUETYPE) {
1323 /* this is further handled in mono_arch_emit_outarg_vt () */
1324 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1325 ins->opcode = OP_OUTARG_VT;
1326 ins->sreg1 = in->dreg;
1327 ins->klass = in->klass;
1328 ins->inst_p0 = call;
1329 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1330 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1331 MONO_ADD_INS (cfg->cbb, ins);
1333 cfg->flags |= MONO_CFG_HAS_FPOUT;
1335 int dreg = mono_alloc_freg (cfg);
1337 if (ainfo->size == 4) {
1338 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1340 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1342 ins->sreg1 = in->dreg;
1343 MONO_ADD_INS (cfg->cbb, ins);
1346 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1347 cfg->flags |= MONO_CFG_HAS_FPOUT;
1350 g_assert_not_reached ();
1354 /* Emit the signature cookie in the case that there is no
1355 additional argument */
1356 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1357 emit_sig_cookie (cfg, call, cinfo);
1359 if (cinfo->struct_ret) {
1362 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1363 vtarg->sreg1 = call->vret_var->dreg;
1364 vtarg->dreg = mono_alloc_preg (cfg);
1365 MONO_ADD_INS (cfg->cbb, vtarg);
1367 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1371 * Reverse the call->out_args list.
1374 MonoInst *prev = NULL, *list = call->out_args, *next;
1381 call->out_args = prev;
1384 call->stack_usage = cinfo->stack_usage;
1385 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1386 cfg->param_area = MAX (cfg->param_area, 16); /* a0-a3 always present */
1387 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1388 cfg->flags |= MONO_CFG_HAS_CALLS;
1390 * should set more info in call, such as the stack space
1391 * used by the args that needs to be added back to esp
1398 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1400 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1401 ArgInfo *ainfo = ins->inst_p1;
1402 int ovf_size = ainfo->vtsize;
1403 int doffset = ainfo->offset;
1404 int i, soffset, dreg;
1406 if (ainfo->regtype == RegTypeStructByVal) {
1409 for (i = 0; i < ainfo->size; ++i) {
1410 dreg = mono_alloc_ireg (cfg);
1411 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1412 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1413 soffset += sizeof (gpointer);
1416 mini_emit_memcpy (cfg, mips_at, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1417 } else if (ainfo->regtype == RegTypeFP) {
1418 int tmpr = mono_alloc_freg (cfg);
1419 if (ainfo->size == 4)
1420 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1422 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1423 dreg = mono_alloc_freg (cfg);
1424 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1425 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1427 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1431 /* FIXME: alignment? */
1432 if (call->signature->pinvoke) {
1433 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1434 vtcopy->backend.is_pinvoke = 1;
1436 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1439 g_assert (ovf_size > 0);
1441 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1442 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1445 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1447 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1452 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1454 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1455 mono_method_signature (method)->ret);
1458 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1461 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1462 ins->sreg1 = val->dreg + 1;
1463 ins->sreg2 = val->dreg + 2;
1464 MONO_ADD_INS (cfg->cbb, ins);
1467 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1468 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1472 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1475 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) || ((ins)->opcode == OP_ICOMPARE)))
1476 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) || ((ins)->opcode == OP_ICOMPARE_IMM)))
1477 #define ins_rewrite(ins, op, s1, s2) do { \
1478 ins->opcode = (op); \
1479 ins->sreg1 = (s1); \
1480 ins->sreg2 = (s2); \
1484 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1486 MonoInst *ins, *n, *last_ins = NULL;
1490 if (cfg->verbose_level > 2)
1491 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1494 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1495 if (cfg->verbose_level > 2)
1496 mono_print_ins_index (0, ins);
1498 switch (ins->opcode) {
1501 if (ins->opcode == OP_IBEQ)
1503 else if (ins->opcode == OP_IBNE_UN)
1506 g_assert_not_reached ();
1507 g_assert (ins_is_compare(last_ins));
1508 ins_rewrite(ins, op, last_ins->sreg1, last_ins->sreg2);
1509 MONO_DELETE_INS(bb, last_ins);
1513 g_assert (ins_is_compare(last_ins));
1514 last_ins->opcode = OP_MIPS_SLT;
1515 last_ins->dreg = mips_at;
1516 ins_rewrite(ins, OP_MIPS_BNE, mips_at, mips_zero);
1520 g_assert (ins_is_compare(last_ins));
1521 last_ins->opcode = OP_MIPS_SLTU;
1522 last_ins->dreg = mips_at;
1523 ins_rewrite(ins, OP_MIPS_BNE, mips_at, mips_zero);
1527 g_assert (ins_is_compare(last_ins));
1528 ins_rewrite(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
1529 last_ins->dreg = mips_at;
1530 ins_rewrite(ins, OP_MIPS_BNE, mips_at, mips_zero);
1534 g_assert (ins_is_compare(last_ins));
1535 ins_rewrite(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
1536 last_ins->dreg = mips_at;
1537 ins_rewrite(ins, OP_MIPS_BNE, mips_at, mips_zero);
1541 g_assert (ins_is_compare(last_ins));
1542 ins_rewrite(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
1543 last_ins->dreg = mips_at;
1544 ins_rewrite(ins, OP_MIPS_BEQ, mips_at, mips_zero);
1548 g_assert (ins_is_compare(last_ins));
1549 ins_rewrite(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
1550 last_ins->dreg = mips_at;
1551 ins_rewrite(ins, OP_MIPS_BEQ, mips_at, mips_zero);
1555 g_assert (ins_is_compare(last_ins));
1556 ins_rewrite(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
1557 last_ins->dreg = mips_at;
1558 ins_rewrite(ins, OP_MIPS_BNE, mips_at, mips_zero);
1562 g_assert (ins_is_compare(last_ins));
1563 ins_rewrite(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
1564 last_ins->dreg = mips_at;
1565 ins_rewrite(ins, OP_MIPS_BNE, mips_at, mips_zero);
1570 g_assert (ins_is_compare(last_ins));
1571 last_ins->opcode = OP_IXOR;
1572 last_ins->dreg = mono_alloc_ireg(cfg);
1573 ins_rewrite(ins, OP_MIPS_SLTIU, last_ins->dreg, mips_zero);
1578 g_assert_not_reached ();
1583 g_assert_not_reached ();
1588 g_assert (ins_is_compare(last_ins));
1589 ins_rewrite(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
1590 MONO_DELETE_INS(bb, last_ins);
1595 g_assert (ins_is_compare(last_ins));
1596 ins_rewrite(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
1597 MONO_DELETE_INS(bb, last_ins);
1600 case OP_COND_EXC_NE_UN:
1601 g_assert (ins_is_compare(last_ins));
1602 ins_rewrite(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
1603 MONO_DELETE_INS(bb, last_ins);
1606 case OP_COND_EXC_LE_UN:
1607 g_assert (ins_is_compare(last_ins));
1608 ins_rewrite(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
1609 MONO_DELETE_INS(bb, last_ins);
1615 bb->last_ins = last_ins;
1619 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1621 MonoInst *ins, *n, *last_ins = NULL;
1624 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1625 MonoInst *last_ins = ins->prev;
1627 switch (ins->opcode) {
1629 /* remove unnecessary multiplication with 1 */
1630 if (ins->inst_imm == 1) {
1631 if (ins->dreg != ins->sreg1) {
1632 ins->opcode = OP_MOVE;
1634 MONO_DELETE_INS (bb, ins);
1638 int power2 = mono_is_power_of_two (ins->inst_imm);
1640 ins->opcode = OP_SHL_IMM;
1641 ins->inst_imm = power2;
1645 case OP_LOAD_MEMBASE:
1646 case OP_LOADI4_MEMBASE:
1648 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1649 * OP_LOAD_MEMBASE offset(basereg), reg
1651 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1652 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1653 ins->inst_basereg == last_ins->inst_destbasereg &&
1654 ins->inst_offset == last_ins->inst_offset) {
1655 if (ins->dreg == last_ins->sreg1) {
1656 MONO_DELETE_INS (bb, ins);
1659 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1660 ins->opcode = OP_MOVE;
1661 ins->sreg1 = last_ins->sreg1;
1666 * Note: reg1 must be different from the basereg in the second load
1667 * OP_LOAD_MEMBASE offset(basereg), reg1
1668 * OP_LOAD_MEMBASE offset(basereg), reg2
1670 * OP_LOAD_MEMBASE offset(basereg), reg1
1671 * OP_MOVE reg1, reg2
1673 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1674 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1675 ins->inst_basereg != last_ins->dreg &&
1676 ins->inst_basereg == last_ins->inst_basereg &&
1677 ins->inst_offset == last_ins->inst_offset) {
1679 if (ins->dreg == last_ins->dreg) {
1680 MONO_DELETE_INS (bb, ins);
1683 ins->opcode = OP_MOVE;
1684 ins->sreg1 = last_ins->dreg;
1687 //g_assert_not_reached ();
1692 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1693 * OP_LOAD_MEMBASE offset(basereg), reg
1695 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1696 * OP_ICONST reg, imm
1698 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1699 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1700 ins->inst_basereg == last_ins->inst_destbasereg &&
1701 ins->inst_offset == last_ins->inst_offset) {
1702 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1703 ins->opcode = OP_ICONST;
1704 ins->inst_c0 = last_ins->inst_imm;
1705 g_assert_not_reached (); // check this rule
1710 case OP_LOADU1_MEMBASE:
1711 case OP_LOADI1_MEMBASE:
1712 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1713 ins->inst_basereg == last_ins->inst_destbasereg &&
1714 ins->inst_offset == last_ins->inst_offset) {
1715 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1716 ins->sreg1 = last_ins->sreg1;
1719 case OP_LOADU2_MEMBASE:
1720 case OP_LOADI2_MEMBASE:
1721 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1722 ins->inst_basereg == last_ins->inst_destbasereg &&
1723 ins->inst_offset == last_ins->inst_offset) {
1724 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1725 ins->sreg1 = last_ins->sreg1;
1731 ins->opcode = OP_MOVE;
1735 if (ins->dreg == ins->sreg1) {
1736 MONO_DELETE_INS (bb, ins);
1740 * OP_MOVE sreg, dreg
1741 * OP_MOVE dreg, sreg
1743 if (last_ins && last_ins->opcode == OP_MOVE &&
1744 ins->sreg1 == last_ins->dreg &&
1745 ins->dreg == last_ins->sreg1) {
1746 MONO_DELETE_INS (bb, ins);
1754 bb->last_ins = last_ins;
1758 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1760 switch (ins->opcode) {
1761 case OP_ICONV_TO_R_UN: {
1762 static const guint64 adjust_val = 0x4330000000000000ULL;
1763 int msw_reg = mono_alloc_ireg (cfg);
1764 int adj_reg = mono_alloc_freg (cfg);
1765 int tmp_reg = mono_alloc_freg (cfg);
1766 int basereg = mips_sp;
1769 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1770 if (!mips_is_imm16 (offset + 4)) {
1771 basereg = mono_alloc_ireg (cfg);
1772 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1774 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
1775 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
1776 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
1777 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
1778 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1779 ins->opcode = OP_NOP;
1782 case OP_ICONV_TO_R4:
1783 case OP_ICONV_TO_R8: {
1784 /* FIXME: change precision for CEE_CONV_R4 */
1785 static const guint64 adjust_val = 0x4330000080000000ULL;
1786 int msw_reg = mono_alloc_ireg (cfg);
1787 int xored = mono_alloc_ireg (cfg);
1788 int adj_reg = mono_alloc_freg (cfg);
1789 int tmp_reg = mono_alloc_freg (cfg);
1790 int basereg = mips_sp;
1793 if (!mips_is_imm16 (offset + 4)) {
1794 basereg = mono_alloc_ireg (cfg);
1795 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1797 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1798 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
1799 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
1800 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
1801 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
1802 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
1803 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1804 if (ins->opcode == OP_ICONV_TO_R4)
1805 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
1806 ins->opcode = OP_NOP;
1811 int msw_reg = mono_alloc_ireg (cfg);
1812 int basereg = mips_sp;
1815 if (!mips_is_imm16 (offset + 4)) {
1816 basereg = mono_alloc_ireg (cfg);
1817 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1819 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
1820 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
1821 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
1822 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1823 ins->opcode = OP_NOP;
1831 #define NEW_INS(cfg,dest,op) do { \
1832 MONO_INST_NEW((cfg), (dest), (op)); \
1833 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
1837 map_to_reg_reg_op (int op)
1846 case OP_COMPARE_IMM:
1848 case OP_ICOMPARE_IMM:
1864 case OP_LOAD_MEMBASE:
1865 return OP_LOAD_MEMINDEX;
1866 case OP_LOADI4_MEMBASE:
1867 return OP_LOADI4_MEMINDEX;
1868 case OP_LOADU4_MEMBASE:
1869 return OP_LOADU4_MEMINDEX;
1870 case OP_LOADU1_MEMBASE:
1871 return OP_LOADU1_MEMINDEX;
1872 case OP_LOADI2_MEMBASE:
1873 return OP_LOADI2_MEMINDEX;
1874 case OP_LOADU2_MEMBASE:
1875 return OP_LOADU2_MEMINDEX;
1876 case OP_LOADI1_MEMBASE:
1877 return OP_LOADI1_MEMINDEX;
1878 case OP_LOADR4_MEMBASE:
1879 return OP_LOADR4_MEMINDEX;
1880 case OP_LOADR8_MEMBASE:
1881 return OP_LOADR8_MEMINDEX;
1882 case OP_STOREI1_MEMBASE_REG:
1883 return OP_STOREI1_MEMINDEX;
1884 case OP_STOREI2_MEMBASE_REG:
1885 return OP_STOREI2_MEMINDEX;
1886 case OP_STOREI4_MEMBASE_REG:
1887 return OP_STOREI4_MEMINDEX;
1888 case OP_STORE_MEMBASE_REG:
1889 return OP_STORE_MEMINDEX;
1890 case OP_STORER4_MEMBASE_REG:
1891 return OP_STORER4_MEMINDEX;
1892 case OP_STORER8_MEMBASE_REG:
1893 return OP_STORER8_MEMINDEX;
1894 case OP_STORE_MEMBASE_IMM:
1895 return OP_STORE_MEMBASE_REG;
1896 case OP_STOREI1_MEMBASE_IMM:
1897 return OP_STOREI1_MEMBASE_REG;
1898 case OP_STOREI2_MEMBASE_IMM:
1899 return OP_STOREI2_MEMBASE_REG;
1900 case OP_STOREI4_MEMBASE_IMM:
1901 return OP_STOREI4_MEMBASE_REG;
1903 g_assert_not_reached ();
1907 * Remove from the instruction list the instructions that can't be
1908 * represented with very simple instructions with no register
1912 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1914 MonoInst *ins, *next, *temp, *last_ins = NULL;
1918 MONO_BB_FOR_EACH_INS (bb, ins) {
1920 switch (ins->opcode) {
1921 case OP_COMPARE_IMM:
1922 case OP_ICOMPARE_IMM:
1924 /* Branch opts can eliminate the branch */
1925 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1926 ins->opcode = OP_NOP;
1929 if (ins->inst_imm) {
1930 NEW_INS (cfg, temp, OP_ICONST);
1931 temp->inst_c0 = ins->inst_imm;
1932 temp->dreg = mono_alloc_ireg (cfg);
1933 ins->sreg2 = temp->dreg;
1937 ins->sreg2 = mips_zero;
1939 if (ins->opcode == OP_COMPARE_IMM)
1940 ins->opcode = OP_COMPARE;
1941 else if (ins->opcode == OP_ICOMPARE_IMM)
1942 ins->opcode = OP_ICOMPARE;
1945 case OP_IDIV_UN_IMM:
1948 case OP_IREM_UN_IMM:
1949 NEW_INS (cfg, temp, OP_ICONST);
1950 temp->inst_c0 = ins->inst_imm;
1951 temp->dreg = mono_alloc_ireg (cfg);
1952 ins->sreg2 = temp->dreg;
1953 if (ins->opcode == OP_IDIV_IMM)
1954 ins->opcode = OP_IDIV;
1955 else if (ins->opcode == OP_IREM_IMM)
1956 ins->opcode = OP_IREM;
1957 else if (ins->opcode == OP_IDIV_UN_IMM)
1958 ins->opcode = OP_IDIV_UN;
1959 else if (ins->opcode == OP_IREM_UN_IMM)
1960 ins->opcode = OP_IREM_UN;
1962 /* handle rem separately */
1967 if (!mips_is_imm16 (ins->inst_imm)) {
1968 NEW_INS (cfg, temp, OP_ICONST);
1969 temp->inst_c0 = ins->inst_imm;
1970 temp->dreg = mono_alloc_ireg (cfg);
1971 ins->sreg2 = temp->dreg;
1972 ins->opcode = map_to_reg_reg_op (ins->opcode);
1978 /* Branch opts can eliminate the branch */
1979 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1980 ins->opcode = OP_NOP;
1986 * remap compare/branch and compare/set
1987 * to MIPS specific opcodes.
1990 switch (next->opcode) {
2007 ins->opcode = OP_NOP;
2008 next->sreg1 = ins->sreg1;
2009 next->sreg2 = ins->sreg2;
2013 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (next->opcode), __FUNCTION__);
2014 g_assert_not_reached ();
2019 if (!mips_is_imm16 (-ins->inst_imm)) {
2020 NEW_INS (cfg, temp, OP_ICONST);
2021 temp->inst_c0 = ins->inst_imm;
2022 temp->dreg = mono_alloc_ireg (cfg);
2023 ins->sreg2 = temp->dreg;
2024 ins->opcode = map_to_reg_reg_op (ins->opcode);
2031 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2032 NEW_INS (cfg, temp, OP_ICONST);
2033 temp->inst_c0 = ins->inst_imm;
2034 temp->dreg = mono_alloc_ireg (cfg);
2035 ins->sreg2 = temp->dreg;
2036 ins->opcode = map_to_reg_reg_op (ins->opcode);
2043 NEW_INS (cfg, temp, OP_ICONST);
2044 temp->inst_c0 = ins->inst_imm;
2045 temp->dreg = mono_alloc_ireg (cfg);
2046 ins->sreg2 = temp->dreg;
2047 ins->opcode = map_to_reg_reg_op (ins->opcode);
2051 if (ins->inst_imm == 1) {
2052 ins->opcode = OP_MOVE;
2055 if (ins->inst_imm == 0) {
2056 ins->opcode = OP_ICONST;
2060 imm = mono_is_power_of_two (ins->inst_imm);
2062 ins->opcode = OP_SHL_IMM;
2063 ins->inst_imm = imm;
2066 if (!mips_is_imm16 (ins->inst_imm)) {
2067 NEW_INS (cfg, temp, OP_ICONST);
2068 temp->inst_c0 = ins->inst_imm;
2069 temp->dreg = mono_alloc_ireg (cfg);
2070 ins->sreg2 = temp->dreg;
2071 ins->opcode = map_to_reg_reg_op (ins->opcode);
2075 case OP_LOAD_MEMBASE:
2076 case OP_LOADI4_MEMBASE:
2077 case OP_LOADU4_MEMBASE:
2078 case OP_LOADI2_MEMBASE:
2079 case OP_LOADU2_MEMBASE:
2080 case OP_LOADI1_MEMBASE:
2081 case OP_LOADU1_MEMBASE:
2082 case OP_LOADR4_MEMBASE:
2083 case OP_LOADR8_MEMBASE:
2084 case OP_STORE_MEMBASE_REG:
2085 case OP_STOREI4_MEMBASE_REG:
2086 case OP_STOREI2_MEMBASE_REG:
2087 case OP_STOREI1_MEMBASE_REG:
2088 case OP_STORER4_MEMBASE_REG:
2089 case OP_STORER8_MEMBASE_REG:
2090 /* we can do two things: load the immed in a register
2091 * and use an indexed load, or see if the immed can be
2092 * represented as an ad_imm + a load with a smaller offset
2093 * that fits. We just do the first for now, optimize later.
2095 if (mips_is_imm16 (ins->inst_offset))
2097 NEW_INS (cfg, temp, OP_ICONST);
2098 temp->inst_c0 = ins->inst_offset;
2099 temp->dreg = mono_alloc_ireg (cfg);
2100 ins->sreg2 = temp->dreg;
2101 ins->opcode = map_to_reg_reg_op (ins->opcode);
2104 case OP_STORE_MEMBASE_IMM:
2105 case OP_STOREI1_MEMBASE_IMM:
2106 case OP_STOREI2_MEMBASE_IMM:
2107 case OP_STOREI4_MEMBASE_IMM:
2109 if (!ins->inst_imm) {
2110 ins->sreg1 = mips_zero;
2111 ins->opcode = map_to_reg_reg_op (ins->opcode);
2114 NEW_INS (cfg, temp, OP_ICONST);
2115 temp->inst_c0 = ins->inst_imm;
2116 temp->dreg = mono_alloc_ireg (cfg);
2117 ins->sreg1 = temp->dreg;
2118 ins->opcode = map_to_reg_reg_op (ins->opcode);
2120 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2124 NEW_INS (cfg, temp, OP_ICONST);
2125 temp->inst_c0 = (guint32)ins->inst_p0;
2126 temp->dreg = mono_alloc_ireg (cfg);
2127 ins->inst_basereg = temp->dreg;
2128 ins->inst_offset = 0;
2129 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2131 /* make it handle the possibly big ins->inst_offset
2132 * later optimize to use lis + load_membase
2139 bb->last_ins = last_ins;
2140 bb->max_vreg = cfg->next_vreg;
2144 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2146 /* sreg is a float, dreg is an integer reg. mips_at is used a scratch */
2148 mips_truncwd (code, mips_ftemp, sreg);
2150 mips_cvtwd (code, mips_ftemp, sreg);
2152 mips_mfc1 (code, dreg, mips_ftemp);
2155 mips_andi (code, dreg, dreg, 0xff);
2156 else if (size == 2) {
2157 mips_sll (code, dreg, dreg, 16);
2158 mips_srl (code, dreg, dreg, 16);
2162 mips_sll (code, dreg, dreg, 24);
2163 mips_sra (code, dreg, dreg, 24);
2165 else if (size == 2) {
2166 mips_sll (code, dreg, dreg, 16);
2167 mips_sra (code, dreg, dreg, 16);
2174 * emit_load_volatile_arguments:
2176 * Load volatile arguments from the stack to the original input registers.
2177 * Required before a tail call.
2180 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
2182 MonoMethod *method = cfg->method;
2183 MonoMethodSignature *sig;
2188 sig = mono_method_signature (method);
2189 cinfo = calculate_sizes (sig, sig->pinvoke);
2190 if (cinfo->struct_ret) {
2191 ArgInfo *ainfo = &cinfo->ret;
2192 inst = cfg->vret_addr;
2193 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2196 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2197 ArgInfo *ainfo = cinfo->args + i;
2198 inst = cfg->args [i];
2199 if (inst->opcode == OP_REGVAR) {
2200 if (ainfo->regtype == RegTypeGeneral)
2201 mips_move (code, ainfo->reg, inst->dreg);
2202 else if (ainfo->regtype == RegTypeFP)
2203 g_assert_not_reached();
2204 else if (ainfo->regtype == RegTypeBase) {
2207 g_assert_not_reached ();
2209 if (ainfo->regtype == RegTypeGeneral) {
2210 g_assert (mips_is_imm16 (inst->inst_offset));
2211 switch (ainfo->size) {
2213 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2216 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2220 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2223 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2224 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
2227 g_assert_not_reached ();
2230 } else if (ainfo->regtype == RegTypeBase) {
2232 } else if (ainfo->regtype == RegTypeFP) {
2233 g_assert (mips_is_imm16 (inst->inst_offset));
2234 if (ainfo->size == 8)
2235 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2236 else if (ainfo->size == 4)
2237 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2239 g_assert_not_reached ();
2240 } else if (ainfo->regtype == RegTypeStructByVal) {
2242 int doffset = inst->inst_offset;
2244 g_assert (mips_is_imm16 (inst->inst_offset));
2245 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
2246 for (i = 0; i < ainfo->size; ++i) {
2247 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
2248 doffset += sizeof (gpointer);
2250 } else if (ainfo->regtype == RegTypeStructByAddr) {
2251 g_assert (mips_is_imm16 (inst->inst_offset));
2252 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2254 g_assert_not_reached ();
2264 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
2266 int size = cfg->param_area;
2268 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2269 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2274 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2275 if (ppc_is_imm16 (-size)) {
2276 ppc_stwu (code, ppc_r0, -size, ppc_sp);
2278 ppc_load (code, ppc_r11, -size);
2279 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2286 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
2288 int size = cfg->param_area;
2290 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2291 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2296 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2297 if (ppc_is_imm16 (size)) {
2298 ppc_stwu (code, ppc_r0, size, ppc_sp);
2300 ppc_load (code, ppc_r11, size);
2301 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2308 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2313 guint8 *code = cfg->native_code + cfg->code_len;
2314 MonoInst *last_ins = NULL;
2315 guint last_offset = 0;
2319 /* we don't align basic blocks of loops on mips */
2321 if (cfg->verbose_level > 2)
2322 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2324 cpos = bb->max_offset;
2327 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2328 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2329 g_assert (!mono_compile_aot);
2332 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2333 /* this is not thread save, but good enough */
2334 /* fixme: howto handle overflows? */
2335 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
2336 mips_lw (code, mips_temp, mips_at, 0);
2337 mips_addiu (code, mips_temp, mips_temp, 1);
2338 mips_sw (code, mips_temp, mips_at, 0);
2341 MONO_BB_FOR_EACH_INS (bb, ins) {
2342 offset = code - cfg->native_code;
2344 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2346 if (offset > (cfg->code_size - max_len - 16)) {
2347 cfg->code_size *= 2;
2348 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2349 code = cfg->native_code + offset;
2351 mono_debug_record_line_number (cfg, ins, offset);
2352 if (cfg->verbose_level > 2) {
2353 g_print (" @ 0x%x\t", offset);
2354 mono_print_ins_index (ins_cnt++, ins);
2356 /* Check for virtual regs that snuck by */
2357 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
2359 switch (ins->opcode) {
2360 case OP_RELAXED_NOP:
2363 case OP_DUMMY_STORE:
2364 case OP_NOT_REACHED:
2368 g_assert_not_reached();
2370 emit_tls_access (code, ins->dreg, ins->inst_offset);
2374 mips_mult (code, ins->sreg1, ins->sreg2);
2375 mips_mflo (code, ins->dreg);
2376 mips_mfhi (code, ins->dreg+1);
2379 mips_multu (code, ins->sreg1, ins->sreg2);
2380 mips_mflo (code, ins->dreg);
2381 mips_mfhi (code, ins->dreg+1);
2383 case OP_MEMORY_BARRIER:
2388 case OP_STOREI1_MEMBASE_IMM:
2389 mips_load_const (code, mips_temp, ins->inst_imm);
2390 if (mips_is_imm16 (ins->inst_offset)) {
2391 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
2393 mips_load_const (code, mips_at, ins->inst_offset);
2394 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
2397 case OP_STOREI2_MEMBASE_IMM:
2398 mips_load_const (code, mips_temp, ins->inst_imm);
2399 if (mips_is_imm16 (ins->inst_offset)) {
2400 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
2402 mips_load_const (code, mips_at, ins->inst_offset);
2403 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
2406 case OP_STORE_MEMBASE_IMM:
2407 case OP_STOREI4_MEMBASE_IMM:
2408 mips_load_const (code, mips_temp, ins->inst_imm);
2409 if (mips_is_imm16 (ins->inst_offset)) {
2410 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
2412 mips_load_const (code, mips_at, ins->inst_offset);
2413 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
2416 case OP_STOREI1_MEMBASE_REG:
2417 if (mips_is_imm16 (ins->inst_offset)) {
2418 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2420 mips_load_const (code, mips_at, ins->inst_offset);
2421 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2422 mips_sb (code, ins->sreg1, mips_at, 0);
2425 case OP_STOREI2_MEMBASE_REG:
2426 if (mips_is_imm16 (ins->inst_offset)) {
2427 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2429 mips_load_const (code, mips_at, ins->inst_offset);
2430 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2431 mips_sh (code, ins->sreg1, mips_at, 0);
2434 case OP_STORE_MEMBASE_REG:
2435 case OP_STOREI4_MEMBASE_REG:
2436 if (mips_is_imm16 (ins->inst_offset)) {
2437 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2439 mips_load_const (code, mips_at, ins->inst_offset);
2440 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2441 mips_sw (code, ins->sreg1, mips_at, 0);
2445 g_assert_not_reached ();
2446 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
2447 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
2449 case OP_LOAD_MEMBASE:
2450 case OP_LOADI4_MEMBASE:
2451 case OP_LOADU4_MEMBASE:
2452 if (mips_is_imm16 (ins->inst_offset)) {
2453 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2455 mips_load_const (code, mips_at, ins->inst_offset);
2456 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2457 mips_lw (code, ins->dreg, mips_at, 0);
2460 case OP_LOADI1_MEMBASE:
2461 if (mips_is_imm16 (ins->inst_offset)) {
2462 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2464 mips_load_const (code, mips_at, ins->inst_offset);
2465 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2466 mips_lb (code, ins->dreg, mips_at, 0);
2469 case OP_LOADU1_MEMBASE:
2470 if (mips_is_imm16 (ins->inst_offset)) {
2471 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2473 mips_load_const (code, mips_at, ins->inst_offset);
2474 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2475 mips_lbu (code, ins->dreg, mips_at, 0);
2478 case OP_LOADI2_MEMBASE:
2479 if (mips_is_imm16 (ins->inst_offset)) {
2480 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2482 mips_load_const (code, mips_at, ins->inst_offset);
2483 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2484 mips_lh (code, ins->dreg, mips_at, 0);
2487 case OP_LOADU2_MEMBASE:
2488 if (mips_is_imm16 (ins->inst_offset)) {
2489 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2491 mips_load_const (code, mips_at, ins->inst_offset);
2492 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2493 mips_lhu (code, ins->dreg, mips_at, 0);
2497 mips_sll (code, mips_at, ins->sreg1, 24);
2498 mips_sra (code, ins->dreg, mips_at, 24);
2501 mips_sll (code, mips_at, ins->sreg1, 16);
2502 mips_sra (code, ins->dreg, mips_at, 16);
2505 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
2508 mips_sll (code, mips_at, ins->sreg1, 16);
2509 mips_srl (code, ins->dreg, mips_at, 16);
2512 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
2515 g_assert (mips_is_imm16 (ins->inst_imm));
2516 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
2519 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
2522 g_assert (mips_is_imm16 (ins->inst_imm));
2523 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
2525 case OP_COMPARE_IMM:
2526 g_assert_not_reached ();
2529 g_assert_not_reached ();
2532 mips_break (code, 0xfd);
2535 g_assert_not_reached ();
2538 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
2541 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
2544 g_assert_not_reached ();
2547 g_assert_not_reached ();
2551 if (mips_is_imm16 (ins->inst_imm)) {
2552 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
2554 mips_load_const (code, mips_at, ins->inst_imm);
2555 mips_addu (code, ins->dreg, ins->sreg1, mips_at);
2559 g_assert_not_reached ();
2562 /* rewritten in .brg file */
2563 g_assert_not_reached ();
2565 case CEE_ADD_OVF_UN:
2566 /* rewritten in .brg file */
2567 g_assert_not_reached ();
2570 /* rewritten in .brg file */
2571 g_assert_not_reached ();
2573 case CEE_SUB_OVF_UN:
2574 /* rewritten in .brg file */
2575 g_assert_not_reached ();
2577 case OP_ADD_OVF_CARRY:
2578 /* rewritten in .brg file */
2579 g_assert_not_reached ();
2581 case OP_ADD_OVF_UN_CARRY:
2582 /* rewritten in .brg file */
2583 g_assert_not_reached ();
2585 case OP_SUB_OVF_CARRY:
2586 /* rewritten in .brg file */
2587 g_assert_not_reached ();
2589 case OP_SUB_OVF_UN_CARRY:
2590 /* rewritten in .brg file */
2591 g_assert_not_reached ();
2595 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2598 /* rewritten in .brg file */
2599 g_assert_not_reached ();
2602 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2606 // we add the negated value
2607 if (mips_is_imm16 (-ins->inst_imm))
2608 mips_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2610 mips_load_const (code, mips_at, ins->inst_imm);
2611 mips_subu (code, ins->dreg, ins->sreg1, mips_at);
2616 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2619 g_assert_not_reached ();
2622 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2626 if (mips_is_imm16 (ins->inst_imm)) {
2627 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2629 mips_load_const (code, mips_at, ins->inst_imm);
2630 mips_and (code, ins->dreg, ins->sreg1, mips_at);
2635 guint32 *divisor_is_m1;
2636 guint32 *divisor_is_zero;
2639 mips_addiu (code, mips_at, mips_zero, 0xffff);
2640 divisor_is_m1 = (guint32 *)code;
2641 mips_bne (code, ins->sreg2, mips_at, 0);
2644 /* Divide by -1 -- throw exception */
2645 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
2647 mips_patch (divisor_is_m1, (guint32)code);
2649 /* Put divide in branch delay slot (NOT YET) */
2650 divisor_is_zero = (guint32 *)code;
2651 mips_bne (code, ins->sreg2, mips_zero, 0);
2654 /* Divide by zero -- throw exception */
2655 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2657 mips_patch (divisor_is_zero, (guint32)code);
2658 mips_div (code, ins->sreg1, ins->sreg2);
2659 if (ins->opcode == OP_IDIV)
2660 mips_mflo (code, ins->dreg);
2662 mips_mfhi (code, ins->dreg);
2666 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2668 /* Put divide in branch delay slot (NOT YET) */
2669 mips_bne (code, ins->sreg2, mips_zero, 0);
2672 /* Divide by zero -- throw exception */
2673 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2675 mips_patch (divisor_is_zero, (guint32)code);
2676 mips_divu (code, ins->sreg1, ins->sreg2);
2677 mips_mflo (code, ins->dreg);
2681 g_assert_not_reached ();
2683 ppc_load (code, ppc_r11, ins->inst_imm);
2684 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2685 ppc_mfspr (code, ppc_r0, ppc_xer);
2686 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2687 /* FIXME: use OverflowException for 0x80000000/-1 */
2688 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2690 g_assert_not_reached();
2693 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2695 /* Put divide in branch delay slot (NOT YET) */
2696 mips_bne (code, ins->sreg2, mips_zero, 0);
2699 /* Divide by zero -- throw exception */
2700 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2702 mips_patch (divisor_is_zero, (guint32)code);
2703 mips_divu (code, ins->sreg1, ins->sreg2);
2704 mips_mfhi (code, ins->dreg);
2708 g_assert_not_reached ();
2710 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2714 if (mips_is_imm16 (ins->inst_imm)) {
2715 mips_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2717 mips_load_const (code, mips_at, ins->inst_imm);
2718 mips_or (code, ins->dreg, ins->sreg1, mips_at);
2722 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2726 /* unsigned 16-bit immediate */
2727 if ((ins->inst_imm & 0xffff) == ins->inst_imm) {
2728 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2730 mips_load_const (code, mips_at, ins->inst_imm);
2731 mips_xor (code, ins->dreg, ins->sreg1, mips_at);
2735 g_assert (mips_is_imm16 (ins->inst_imm));
2736 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2739 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
2743 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2746 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
2750 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2753 case OP_ISHR_UN_IMM:
2754 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2757 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
2760 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
2763 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
2767 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2769 mips_mult (code, ins->sreg1, ins->sreg2);
2770 mips_mflo (code, ins->dreg);
2777 mips_load_const (code, mips_at, ins->inst_imm);
2779 mips_mul (code, ins->dreg, ins->sreg1, mips_at);
2781 mips_mult (code, ins->sreg1, mips_at);
2782 mips_mflo (code, ins->dreg);
2789 mips_mult (code, ins->sreg1, ins->sreg2);
2790 mips_mflo (code, ins->dreg);
2791 mips_mfhi (code, mips_at);
2794 mips_sra (code, mips_temp, ins->dreg, 31);
2795 patch = (guint32 *)(void *)code;
2796 mips_beq (code, mips_temp, mips_at, 0);
2798 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
2799 mips_patch (patch, (guint32)code);
2802 case CEE_MUL_OVF_UN:
2804 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2806 mips_mult (code, ins->sreg1, ins->sreg2);
2807 mips_mflo (code, ins->dreg);
2808 mips_mfhi (code, mips_at);
2812 /* XXX - Throw exception if we overflowed */
2815 mips_load_const (code, ins->dreg, ins->inst_c0);
2818 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2819 mips_load (code, ins->dreg, 0);
2823 mips_mtc1 (code, ins->dreg, ins->sreg1);
2826 mips_mfc1 (code, ins->dreg, ins->sreg1);
2829 mips_dmtc1 (code, ins->dreg, ins->sreg1);
2832 mips_dmfc1 (code, ins->dreg, ins->sreg1);
2838 if (ins->dreg != ins->sreg1)
2839 mips_move (code, ins->dreg, ins->sreg1);
2842 /* Get sreg1 into v1, sreg2 into v0 */
2844 if (ins->sreg1 == mips_v0) {
2845 if (ins->sreg1 != mips_at)
2846 mips_move (code, mips_at, ins->sreg1);
2847 if (ins->sreg2 != mips_v0)
2848 mips_move (code, mips_v0, ins->sreg2);
2849 mips_move (code, mips_v1, mips_at);
2852 if (ins->sreg2 != mips_v0)
2853 mips_move (code, mips_v0, ins->sreg2);
2854 if (ins->sreg1 != mips_v1)
2855 mips_move (code, mips_v1, ins->sreg1);
2859 if (ins->dreg != ins->sreg1) {
2860 mips_fmovd (code, ins->dreg, ins->sreg1);
2864 /* Convert from double to float and leave it there */
2865 mips_cvtsd (code, ins->dreg, ins->sreg1);
2867 case OP_FCONV_TO_R4:
2868 /* Convert from double to float and back again */
2869 mips_cvtsd (code, ins->dreg, ins->sreg1);
2870 mips_cvtds (code, ins->dreg, ins->dreg);
2873 code = emit_load_volatile_arguments(cfg, code);
2876 * Pop our stack, then jump to specified method (tail-call)
2877 * Keep in sync with mono_arch_emit_epilog
2879 code = mono_arch_emit_epilog_sub (cfg, code);
2881 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
2882 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2884 mips_lui (code, mips_t9, mips_zero, 0);
2885 mips_addiu (code, mips_t9, mips_t9, 0);
2886 mips_jr (code, mips_t9);
2889 mips_beq (code, mips_zero, mips_zero, 0);
2894 /* ensure ins->sreg1 is not NULL */
2895 mips_lw (code, mips_zero, ins->sreg1, 0);
2898 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2899 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2901 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
2902 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
2904 mips_sw (code, mips_at, ins->sreg1, 0);
2917 case OP_VOIDCALL_REG:
2919 case OP_FCALL_MEMBASE:
2920 case OP_LCALL_MEMBASE:
2921 case OP_VCALL_MEMBASE:
2922 case OP_VCALL2_MEMBASE:
2923 case OP_VOIDCALL_MEMBASE:
2924 case OP_CALL_MEMBASE:
2925 call = (MonoCallInst*)ins;
2926 switch (ins->opcode) {
2933 if (ins->flags & MONO_INST_HAS_METHOD)
2934 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2936 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2937 mips_lui (code, mips_t9, mips_zero, 0);
2938 mips_addiu (code, mips_t9, mips_t9, 0);
2944 case OP_VOIDCALL_REG:
2946 mips_move (code, mips_t9, ins->sreg1);
2948 case OP_FCALL_MEMBASE:
2949 case OP_LCALL_MEMBASE:
2950 case OP_VCALL_MEMBASE:
2951 case OP_VCALL2_MEMBASE:
2952 case OP_VOIDCALL_MEMBASE:
2953 case OP_CALL_MEMBASE:
2954 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
2957 mips_jalr (code, mips_t9, mips_ra);
2959 if ((ins->opcode == OP_FCALL ||
2960 ins->opcode == OP_FCALL_REG) &&
2961 call->signature->ret->type == MONO_TYPE_R4) {
2962 mips_cvtds (code, mips_f0, mips_f0);
2966 int area_offset = cfg->param_area;
2968 /* Round up ins->sreg1, mips_at ends up holding size */
2969 mips_addiu (code, mips_at, ins->sreg1, 31);
2970 mips_andi (code, mips_at, mips_at, ~31);
2972 mips_subu (code, mips_sp, mips_sp, mips_at);
2973 mips_addiu (code, ins->dreg, mips_sp, area_offset);
2975 if (ins->flags & MONO_INST_INIT) {
2976 mips_move (code, mips_temp, ins->dreg);
2977 mips_sb (code, mips_zero, mips_temp, 0);
2978 mips_addiu (code, mips_at, mips_at, -1);
2979 mips_bne (code, mips_at, mips_zero, -4);
2980 mips_addiu (code, mips_temp, mips_temp, 1);
2985 gpointer addr = mono_arch_get_throw_exception();
2986 mips_move (code, mips_a0, ins->sreg1);
2987 mips_load_const (code, mips_t9, addr);
2988 mips_jalr (code, mips_t9, mips_ra);
2990 mips_break (code, 0xfc);
2994 gpointer addr = mono_arch_get_rethrow_exception();
2995 mips_move (code, mips_a0, ins->sreg1);
2996 mips_load_const (code, mips_t9, addr);
2997 mips_jalr (code, mips_t9, mips_ra);
2999 mips_break (code, 0xfb);
3002 case OP_START_HANDLER: {
3004 * The START_HANDLER instruction marks the beginning of
3005 * a handler block. It is called using a call
3006 * instruction, so mips_ra contains the return address.
3007 * Since the handler executes in the same stack frame
3008 * as the method itself, we can't use save/restore to
3009 * save the return address. Instead, we save it into
3010 * a dedicated variable.
3012 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3013 g_assert (spvar->inst_basereg != mips_sp);
3014 code = emit_reserve_param_area (cfg, code);
3016 if (mips_is_imm16 (spvar->inst_offset)) {
3017 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3019 mips_load_const (code, mips_at, spvar->inst_offset);
3020 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3021 mips_sw (code, mips_ra, mips_at, 0);
3025 case OP_ENDFILTER: {
3026 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3027 g_assert (spvar->inst_basereg != mips_sp);
3028 code = emit_unreserve_param_area (cfg, code);
3030 if (ins->sreg1 != mips_v0)
3031 mips_move (code, mips_v0, ins->sreg1);
3032 if (mips_is_imm16 (spvar->inst_offset)) {
3033 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3035 mips_load_const (code, mips_at, spvar->inst_offset);
3036 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3037 mips_lw (code, mips_ra, mips_at, 0);
3039 mips_jr (code, mips_ra);
3043 case OP_ENDFINALLY: {
3044 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3045 g_assert (spvar->inst_basereg != mips_sp);
3046 code = emit_unreserve_param_area (cfg, code);
3047 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3048 mips_jalr (code, mips_t9, mips_ra);
3052 case OP_CALL_HANDLER:
3053 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3054 mips_lui (code, mips_t9, mips_zero, 0);
3055 mips_addiu (code, mips_t9, mips_t9, 0);
3056 mips_jalr (code, mips_t9, mips_ra);
3060 ins->inst_c0 = code - cfg->native_code;
3063 if (ins->flags & MONO_INST_BRLABEL) {
3064 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3066 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3069 mips_lui (code, mips_at, mips_zero, 0);
3070 mips_addiu (code, mips_at, mips_at, 0);
3071 mips_jr (code, mips_at);
3074 mips_beq (code, mips_zero, mips_zero, 0);
3079 mips_jr (code, ins->sreg1);
3085 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3086 if (offset > (cfg->code_size - max_len - 16)) {
3087 cfg->code_size += max_len;
3088 cfg->code_size *= 2;
3089 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3090 code = cfg->native_code + offset;
3092 g_assert (ins->sreg1 != -1);
3093 mips_sll (code, mips_at, ins->sreg1, 2);
3094 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3095 mips_move (code, mips_t8, mips_ra);
3096 mips_bgezal (code, mips_zero, 1); /* bal */
3098 mips_addu (code, mips_t9, mips_ra, mips_at);
3099 /* Table is 16 or 20 bytes from target of bal above */
3100 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3101 mips_move (code, mips_ra, mips_t8);
3102 mips_lw (code, mips_t9, mips_t9, 20);
3105 mips_lw (code, mips_t9, mips_t9, 16);
3106 mips_jalr (code, mips_t9, mips_t8);
3108 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3109 mips_emit32 (code, 0xfefefefe);
3114 mips_addiu (code, ins->dreg, mips_zero, 1);
3115 mips_beq (code, mips_at, mips_zero, 2);
3117 mips_move (code, ins->dreg, mips_zero);
3123 mips_addiu (code, ins->dreg, mips_zero, 1);
3124 mips_bltz (code, mips_at, 2);
3126 mips_move (code, ins->dreg, mips_zero);
3132 mips_addiu (code, ins->dreg, mips_zero, 1);
3133 mips_bgtz (code, mips_at, 2);
3135 mips_move (code, ins->dreg, mips_zero);
3138 case OP_COND_EXC_EQ:
3139 case OP_COND_EXC_GE:
3140 case OP_COND_EXC_GT:
3141 case OP_COND_EXC_LE:
3142 case OP_COND_EXC_LT:
3143 case OP_COND_EXC_NE_UN:
3144 case OP_COND_EXC_GE_UN:
3145 case OP_COND_EXC_GT_UN:
3146 case OP_COND_EXC_LE_UN:
3147 case OP_COND_EXC_LT_UN:
3149 case OP_COND_EXC_OV:
3150 case OP_COND_EXC_NO:
3152 case OP_COND_EXC_NC:
3154 case OP_COND_EXC_IEQ:
3155 case OP_COND_EXC_IGE:
3156 case OP_COND_EXC_IGT:
3157 case OP_COND_EXC_ILE:
3158 case OP_COND_EXC_ILT:
3159 case OP_COND_EXC_INE_UN:
3160 case OP_COND_EXC_IGE_UN:
3161 case OP_COND_EXC_IGT_UN:
3162 case OP_COND_EXC_ILE_UN:
3163 case OP_COND_EXC_ILT_UN:
3165 case OP_COND_EXC_IOV:
3166 case OP_COND_EXC_INO:
3167 case OP_COND_EXC_IC:
3168 case OP_COND_EXC_INC:
3169 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
3170 g_warning ("unsupported conditional exception %s\n", mono_inst_name (ins->opcode));
3171 g_assert_not_reached ();
3174 case OP_MIPS_COND_EXC_EQ:
3175 case OP_MIPS_COND_EXC_GE:
3176 case OP_MIPS_COND_EXC_GT:
3177 case OP_MIPS_COND_EXC_LE:
3178 case OP_MIPS_COND_EXC_LT:
3179 case OP_MIPS_COND_EXC_NE_UN:
3180 case OP_MIPS_COND_EXC_GE_UN:
3181 case OP_MIPS_COND_EXC_GT_UN:
3182 case OP_MIPS_COND_EXC_LE_UN:
3183 case OP_MIPS_COND_EXC_LT_UN:
3185 case OP_MIPS_COND_EXC_OV:
3186 case OP_MIPS_COND_EXC_NO:
3187 case OP_MIPS_COND_EXC_C:
3188 case OP_MIPS_COND_EXC_NC:
3190 case OP_MIPS_COND_EXC_IEQ:
3191 case OP_MIPS_COND_EXC_IGE:
3192 case OP_MIPS_COND_EXC_IGT:
3193 case OP_MIPS_COND_EXC_ILE:
3194 case OP_MIPS_COND_EXC_ILT:
3195 case OP_MIPS_COND_EXC_INE_UN:
3196 case OP_MIPS_COND_EXC_IGE_UN:
3197 case OP_MIPS_COND_EXC_IGT_UN:
3198 case OP_MIPS_COND_EXC_ILE_UN:
3199 case OP_MIPS_COND_EXC_ILT_UN:
3201 case OP_MIPS_COND_EXC_IOV:
3202 case OP_MIPS_COND_EXC_INO:
3203 case OP_MIPS_COND_EXC_IC:
3204 case OP_MIPS_COND_EXC_INC: {
3208 /* If the condition is true, raise the exception */
3210 /* need to reverse test to skip around exception raising */
3212 /* For the moment, branch around a branch to avoid reversing
3215 /* Remember, an unpatched branch to 0 branches to the delay slot */
3216 switch (ins->opcode) {
3217 case OP_MIPS_COND_EXC_EQ:
3218 throw = (guint32 *)(void *)code;
3219 mips_beq (code, ins->sreg1, ins->sreg2, 0);
3222 case OP_MIPS_COND_EXC_NE_UN:
3223 throw = (guint32 *)(void *)code;
3224 mips_bne (code, ins->sreg1, ins->sreg2, 0);
3227 case OP_MIPS_COND_EXC_LE_UN:
3228 mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
3229 throw = (guint32 *)(void *)code;
3230 mips_blez (code, mips_at, 0);
3234 /* Not yet implemented */
3235 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
3236 g_assert_not_reached ();
3238 skip = (guint32 *)(void *)code;
3239 mips_beq (code, mips_zero, mips_zero, 0);
3241 mips_patch (throw, (guint32)code);
3242 code = mips_emit_exc_by_name (code, ins->inst_p1);
3243 mips_patch (skip, (guint32)code);
3244 cfg->bb_exit->max_offset += 24;
3257 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
3258 g_warning ("unsupported conditional set %s\n", mono_inst_name (ins->opcode));
3259 g_assert_not_reached ();
3267 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
3270 /* floating point opcodes */
3272 if (((guint32)ins->inst_p0) & (1 << 15))
3273 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
3275 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
3276 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
3279 if (((guint32)ins->inst_p0) & (1 << 15))
3280 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
3282 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
3283 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
3284 mips_cvtds (code, ins->dreg, ins->dreg);
3286 case OP_STORER8_MEMBASE_REG:
3287 if (mips_is_imm16 (ins->inst_offset)) {
3289 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3291 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
3292 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
3295 mips_load_const (code, mips_at, ins->inst_offset);
3296 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3297 mips_swc1 (code, ins->sreg1, mips_at, 4);
3298 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
3301 case OP_LOADR8_MEMBASE:
3302 if (mips_is_imm16 (ins->inst_offset)) {
3304 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3306 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
3307 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
3310 mips_load_const (code, mips_at, ins->inst_offset);
3311 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3312 mips_lwc1 (code, ins->dreg, mips_at, 4);
3313 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
3316 case OP_STORER4_MEMBASE_REG:
3317 /* XXX Need to convert ins->sreg1 to single-precision first */
3318 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3319 if (mips_is_imm16 (ins->inst_offset)) {
3320 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
3322 mips_load_const (code, mips_at, ins->inst_offset);
3323 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3324 mips_swc1 (code, mips_ftemp, mips_at, 0);
3328 if (mips_is_imm16 (ins->inst_offset)) {
3329 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3331 mips_load_const (code, mips_at, ins->inst_offset);
3332 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3333 mips_lwc1 (code, ins->dreg, mips_at, 0);
3336 case OP_LOADR4_MEMBASE:
3337 if (mips_is_imm16 (ins->inst_offset)) {
3338 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3340 mips_load_const (code, mips_at, ins->inst_offset);
3341 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3342 mips_lwc1 (code, ins->dreg, mips_at, 0);
3344 /* Convert to double precision in place */
3345 mips_cvtds (code, ins->dreg, ins->dreg);
3347 case CEE_CONV_R_UN: {
3348 static const guint64 adjust_val = 0x41F0000000000000ULL;
3350 /* convert unsigned int to double */
3351 mips_mtc1 (code, mips_ftemp, ins->sreg1);
3352 mips_bgez (code, ins->sreg1, 5);
3353 mips_cvtdw (code, ins->dreg, mips_ftemp);
3355 mips_load (code, mips_at, (guint32) &adjust_val);
3356 mips_ldc1 (code, mips_ftemp, mips_at, 0);
3357 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
3358 /* target is here */
3362 mips_mtc1 (code, mips_ftemp, ins->sreg1);
3363 mips_cvtsw (code, ins->dreg, mips_ftemp);
3364 mips_cvtds (code, ins->dreg, ins->dreg);
3367 mips_mtc1 (code, mips_ftemp, ins->sreg1);
3368 mips_cvtdw (code, ins->dreg, mips_ftemp);
3370 case OP_FCONV_TO_I1:
3371 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3373 case OP_FCONV_TO_U1:
3374 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3376 case OP_FCONV_TO_I2:
3377 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3379 case OP_FCONV_TO_U2:
3380 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3382 case OP_FCONV_TO_I4:
3384 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3386 case OP_FCONV_TO_U4:
3388 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3390 case OP_FCONV_TO_I8:
3391 case OP_FCONV_TO_U8:
3392 g_assert_not_reached ();
3393 /* Implemented as helper calls */
3395 case OP_LCONV_TO_R_UN:
3396 g_assert_not_reached ();
3397 /* Implemented as helper calls */
3399 case OP_LCONV_TO_OVF_I:
3400 g_assert_not_reached ();
3401 /* split up by brg file */
3404 mips_fsqrtd (code, ins->dreg, ins->sreg1);
3407 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
3410 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
3413 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
3416 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
3419 mips_fnegd (code, ins->dreg, ins->sreg1);
3423 g_assert_not_reached ();
3426 g_assert_not_reached();
3429 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
3430 mips_addiu (code, ins->dreg, mips_zero, 1);
3431 mips_fbtrue (code, 2);
3433 mips_move (code, ins->dreg, mips_zero);
3436 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
3437 mips_addiu (code, ins->dreg, mips_zero, 1);
3438 mips_fbtrue (code, 2);
3440 mips_move (code, ins->dreg, mips_zero);
3443 /* Less than, or Unordered */
3444 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
3445 mips_addiu (code, ins->dreg, mips_zero, 1);
3446 mips_fbtrue (code, 2);
3448 mips_move (code, ins->dreg, mips_zero);
3451 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
3452 mips_move (code, ins->dreg, mips_zero);
3453 mips_fbtrue (code, 2);
3455 mips_addiu (code, ins->dreg, mips_zero, 1);
3458 /* Greater than, or Unordered */
3459 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
3460 mips_move (code, ins->dreg, mips_zero);
3461 mips_fbtrue (code, 2);
3463 mips_addiu (code, ins->dreg, mips_zero, 1);
3466 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
3468 if (ins->flags & MONO_INST_BRLABEL)
3469 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3471 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3472 mips_fbtrue (code, 0);
3476 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
3478 if (ins->flags & MONO_INST_BRLABEL)
3479 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3481 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3482 mips_fbfalse (code, 0);
3486 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
3488 if (ins->flags & MONO_INST_BRLABEL)
3489 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3491 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3492 mips_fbtrue (code, 0);
3496 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
3498 if (ins->flags & MONO_INST_BRLABEL)
3499 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3501 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3502 mips_fbtrue (code, 0);
3506 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
3508 if (ins->flags & MONO_INST_BRLABEL)
3509 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3511 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3512 mips_fbfalse (code, 0);
3516 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
3518 if (ins->flags & MONO_INST_BRLABEL)
3519 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3521 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3522 mips_fbfalse (code, 0);
3526 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
3528 if (ins->flags & MONO_INST_BRLABEL)
3529 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3531 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3532 mips_fbfalse (code, 0);
3536 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
3538 if (ins->flags & MONO_INST_BRLABEL)
3539 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3541 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3542 mips_fbfalse (code, 0);
3546 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
3548 if (ins->flags & MONO_INST_BRLABEL)
3549 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3551 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3552 mips_fbtrue (code, 0);
3556 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
3558 if (ins->flags & MONO_INST_BRLABEL)
3559 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3561 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3562 mips_fbtrue (code, 0);
3566 g_assert_not_reached();
3568 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
3569 ppc_lwz (code, ppc_r11, -8, ppc_sp);
3570 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
3571 ppc_addis (code, ppc_r11, ppc_r11, -32752);
3572 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
3573 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3578 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3579 mips_load (code, ins->dreg, 0x0f0f0f0f);
3584 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3585 g_assert_not_reached ();
3588 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3589 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3590 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3591 g_assert_not_reached ();
3597 last_offset = offset;
3600 cfg->code_len = code - cfg->native_code;
3604 mono_arch_register_lowlevel_calls (void)
3609 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3611 MonoJumpInfo *patch_info;
3613 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3614 unsigned char *ip = patch_info->ip.i + code;
3615 const unsigned char *target;
3617 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3619 switch (patch_info->type) {
3620 case MONO_PATCH_INFO_IP:
3621 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
3623 case MONO_PATCH_INFO_SWITCH: {
3624 /* jt is the inlined jump table, 7 or 9 instructions after ip
3625 * In the normal case we store the absolute addresses.
3626 * otherwise the displacements.
3629 gpointer *table = (gpointer *)patch_info->data.table->table;
3630 gpointer *jt = ((gpointer*)(void *)ip) + 7;
3631 if (1 /* || !(cfg->->flags & MONO_CFG_HAS_CALLS) */)
3633 for (i = 0; i < patch_info->data.table->table_size; i++) {
3634 jt [i] = code + (int)table [i];
3638 case MONO_PATCH_INFO_METHODCONST:
3639 case MONO_PATCH_INFO_CLASS:
3640 case MONO_PATCH_INFO_IMAGE:
3641 case MONO_PATCH_INFO_FIELD:
3642 case MONO_PATCH_INFO_VTABLE:
3643 case MONO_PATCH_INFO_IID:
3644 case MONO_PATCH_INFO_SFLDA:
3645 case MONO_PATCH_INFO_LDSTR:
3646 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3647 case MONO_PATCH_INFO_LDTOKEN:
3648 case MONO_PATCH_INFO_R4:
3649 case MONO_PATCH_INFO_R8:
3650 /* from OP_AOTCONST : lui + addiu */
3651 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
3654 case MONO_PATCH_INFO_EXC_NAME:
3655 g_assert_not_reached ();
3656 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
3659 case MONO_PATCH_INFO_NONE:
3660 /* everything is dealt with at epilog output time */
3665 mips_patch ((guint32 *)(void *)ip, (guint32)target);
3671 mono_trace_lmf_prolog (MonoLMF *new_lmf)
3677 mono_trace_lmf_epilog (MonoLMF *old_lmf)
3682 * Allow tracing to work with this interface (with an optional argument)
3684 * This code is expected to be inserted just after the 'real' prolog code,
3685 * and before the first basic block. We need to allocate a 2nd, temporary
3686 * stack frame so that we can preserve f12-f15 as well as a0-a3.
3690 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3693 int fp_stack_offset = 0;
3699 mips_sw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3700 mips_sw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3701 mips_sw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3702 mips_sw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3705 fp_stack_offset = MIPS_STACK_PARAM_OFFSET;
3706 mips_addiu (code, mips_sp, mips_sp, -64);
3707 mips_swc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3708 mips_swc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3709 mips_swc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3710 mips_swc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3712 mips_fmovs (code, mips_f22, mips_f12);
3713 mips_fmovs (code, mips_f23, mips_f13);
3714 mips_fmovs (code, mips_f24, mips_f14);
3715 mips_fmovs (code, mips_f25, mips_f15);
3718 mips_load_const (code, mips_a0, cfg->method);
3719 mips_addiu (code, mips_a1, mips_sp, cfg->stack_offset + fp_stack_offset);
3720 mips_load_const (code, mips_t9, func);
3721 mips_jalr (code, mips_t9, mips_ra);
3724 mips_lw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3725 mips_lw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3726 mips_lw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3727 mips_lw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3730 mips_lwc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3731 mips_lwc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3732 mips_lwc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3733 mips_lwc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3734 mips_addiu (code, mips_sp, mips_sp, 64);
3736 mips_fmovs (code, mips_f12, mips_f22);
3737 mips_fmovs (code, mips_f13, mips_f23);
3738 mips_fmovs (code, mips_f14, mips_f24);
3739 mips_fmovs (code, mips_f15, mips_f25);
3749 mips_adjust_stackframe(MonoCompile *cfg)
3752 int delta, threshold, i;
3753 MonoMethodSignature *sig;
3754 int verbose = (cfg->verbose_level > 2);
3756 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
3759 /* re-align cfg->stack_offset if needed (due to var spilling) */
3760 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
3761 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
3763 g_print ("mips_adjust_stackframe:\n");
3764 g_print ("\tspillvars allocated 0x%x -> 0x%x (+%d)\n", cfg->arch.local_alloc_offset, cfg->stack_offset, delta);
3766 threshold = cfg->arch.local_alloc_offset - 4;
3769 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
3770 cfg->vret_addr->inst_offset += delta;
3773 sig = mono_method_signature (cfg->method);
3774 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3775 MonoInst *inst = cfg->args [i];
3777 inst->inst_offset += delta;
3782 * loads and stores based off the frame reg that (used to) lie
3783 * above the spill var area need to be increased by 'delta'
3784 * to make room for the spill vars.
3786 /* Need to find loads and stores to adjust that
3787 * are above where the spillvars were inserted, but
3788 * which are not the spillvar references themselves.
3790 * Idea - since all offsets from fp are positive, make
3791 * spillvar offsets negative to begin with so we can spot
3796 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3801 g_print ("BASIC BLOCK %d:\n", bb->block_num);
3803 MONO_BB_FOR_EACH_INS (bb, ins) {
3805 mono_print_ins_index (ins_cnt, ins);
3807 if ((MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp)) || (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))) {
3808 if (ins->inst_c0 > threshold) {
3809 ins->inst_c0 += delta;
3812 mono_print_ins_index (ins_cnt, ins);
3815 else if (ins->inst_c0 < 0) {
3816 ins->inst_c0 = - ins->inst_c0;
3819 mono_print_ins_index (ins_cnt, ins);
3830 * Stack frame layout:
3832 * ------------------- sp + cfg->stack_usage + cfg->param_area
3833 * param area incoming
3834 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
3836 * ------------------- sp + cfg->stack_usage
3838 * ------------------- sp + cfg->stack_usage-4
3840 * ------------------- sp +
3841 * MonoLMF structure optional
3842 * ------------------- sp + cfg->arch.lmf_offset
3843 * saved registers s0-s8
3844 * ------------------- sp + cfg->arch.iregs_offset
3846 * ------------------- sp + cfg->param_area
3847 * param area outgoing
3848 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
3850 * ------------------- sp
3854 mono_arch_emit_prolog (MonoCompile *cfg)
3856 MonoMethod *method = cfg->method;
3857 MonoMethodSignature *sig;
3859 int alloc_size, pos, i;
3863 guint32 iregs_to_save = 0;
3865 guint32 fregs_to_save = 0;
3868 /* lmf_offset is the offset of the LMF from our stack pointer. */
3869 guint32 lmf_offset = cfg->arch.lmf_offset;
3872 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3876 cfg->flags |= MONO_CFG_HAS_CALLS;
3878 sig = mono_method_signature (method);
3879 cfg->code_size = 768 + sig->param_count * 20;
3880 code = cfg->native_code = g_malloc (cfg->code_size);
3882 /* adjust stackframe assignments for spillvars if needed */
3883 mips_adjust_stackframe (cfg);
3885 /* stack_offset should not be changed here. */
3886 alloc_size = cfg->stack_offset;
3887 cfg->stack_usage = alloc_size;
3890 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
3892 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3896 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3898 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
3899 fregs_to_save |= (fregs_to_save << 1);
3903 if (mips_is_imm16 (-alloc_size)) {
3904 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
3906 mips_load_const (code, mips_at, -alloc_size);
3907 mips_addu (code, mips_sp, mips_sp, mips_at);
3911 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3912 mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
3914 /* XXX - optimize this later to not save all regs if LMF constructed */
3916 if (iregs_to_save) {
3917 /* save used registers in own stack frame (at pos) */
3918 pos = cfg->arch.iregs_offset;
3919 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3920 if (iregs_to_save & (1 << i)) {
3921 g_assert (pos < cfg->stack_usage - 4);
3922 mips_sw (code, i, mips_sp, pos);
3923 pos += sizeof (gulong);
3928 if (method->save_lmf) {
3929 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3930 mips_sw (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
3936 /* Save float registers */
3937 if (fregs_to_save) {
3938 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3939 if (fregs_to_save & (1 << i)) {
3940 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3941 mips_swc1 (code, i, mips_sp, pos);
3942 pos += sizeof (gulong);
3947 if (method->save_lmf) {
3948 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3949 mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
3954 if (cfg->frame_reg != mips_sp) {
3955 mips_move (code, cfg->frame_reg, mips_sp);
3957 if (method->save_lmf)
3958 mips_sw (code, cfg->frame_reg, mips_sp,
3959 lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
3963 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
3964 * to the t* registers, which would be clobbered by the instrumentation calls.
3967 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3970 /* load arguments allocated to register from the stack */
3973 cinfo = calculate_sizes (sig, sig->pinvoke);
3975 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3976 ArgInfo *ainfo = &cinfo->ret;
3977 inst = cfg->vret_addr;
3978 if (inst->opcode == OP_REGVAR)
3979 mips_move (code, inst->dreg, ainfo->reg);
3980 else if (mips_is_imm16 (inst->inst_offset)) {
3981 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3983 mips_load_const (code, mips_at, inst->inst_offset);
3984 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
3985 mips_sw (code, ainfo->reg, mips_at, 0);
3988 /* Keep this in sync with emit_load_volatile_arguments */
3989 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3990 ArgInfo *ainfo = cinfo->args + i;
3991 inst = cfg->args [pos];
3993 if (cfg->verbose_level > 2)
3994 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3995 if (inst->opcode == OP_REGVAR) {
3996 /* Argument ends up in a register */
3997 if (ainfo->regtype == RegTypeGeneral)
3998 mips_move (code, inst->dreg, ainfo->reg);
3999 else if (ainfo->regtype == RegTypeFP) {
4000 g_assert_not_reached();
4002 ppc_fmr (code, inst->dreg, ainfo->reg);
4005 else if (ainfo->regtype == RegTypeBase) {
4006 mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
4008 g_assert_not_reached ();
4010 if (cfg->verbose_level > 2)
4011 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4013 /* Argument ends up on the stack */
4014 if (ainfo->regtype == RegTypeGeneral) {
4015 /* Incoming parameters should be above this frame */
4016 if (cfg->verbose_level > 2)
4017 g_print ("stack slot at %d of %d\n", inst->inst_offset, alloc_size);
4018 /* g_assert (inst->inst_offset >= alloc_size); */
4019 g_assert (mips_is_imm16 (inst->inst_offset));
4020 switch (ainfo->size) {
4022 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4025 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4029 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4032 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4033 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
4036 g_assert_not_reached ();
4039 } else if (ainfo->regtype == RegTypeBase) {
4041 * Argument comes in on the stack, and ends up on the stack
4042 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4043 * 8 and 16 bit quantities. Shorten them in place.
4045 g_assert (mips_is_imm16 (inst->inst_offset));
4046 switch (ainfo->size) {
4048 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4049 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4052 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4053 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4060 g_assert_not_reached ();
4062 } else if (ainfo->regtype == RegTypeFP) {
4063 g_assert (mips_is_imm16 (inst->inst_offset));
4064 if (ainfo->size == 8) {
4066 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4068 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
4069 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
4072 else if (ainfo->size == 4)
4073 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4075 g_assert_not_reached ();
4076 } else if (ainfo->regtype == RegTypeStructByVal) {
4078 int doffset = inst->inst_offset;
4080 g_assert (mips_is_imm16 (inst->inst_offset));
4081 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4082 /* Push the argument registers into their stack slots */
4083 for (i = 0; i < ainfo->size; ++i) {
4084 mips_sw (code, ainfo->reg + i, inst->inst_basereg, doffset);
4085 doffset += sizeof (gpointer);
4087 } else if (ainfo->regtype == RegTypeStructByAddr) {
4088 g_assert (mips_is_imm16 (inst->inst_offset));
4089 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4090 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4092 g_assert_not_reached ();
4097 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4098 mips_load_const (code, mips_a0, cfg->domain);
4099 mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
4100 mips_jalr (code, mips_t9, mips_ra);
4105 if (method->save_lmf) {
4106 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
4107 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
4109 if (lmf_pthread_key != -1) {
4110 g_assert_not_reached();
4112 emit_tls_access (code, mips_temp, lmf_pthread_key);
4114 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4115 mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4118 mips_addiu (code, mips_a0, mips_sp, lmf_offset);
4119 mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
4120 mips_jalr (code, mips_t9, mips_ra);
4123 /* This can/will clobber the a0-a3 registers */
4124 mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
4125 mips_jalr (code, mips_t9, mips_ra);
4129 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4130 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4131 /* new_lmf->previous_lmf = *lmf_addr */
4132 mips_lw (code, mips_at, mips_v0, 0);
4133 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4134 /* *(lmf_addr) = sp + lmf_offset */
4135 mips_addiu (code, mips_at, mips_sp, lmf_offset);
4136 mips_sw (code, mips_at, mips_v0, 0);
4138 /* save method info */
4139 mips_load_const (code, mips_at, method);
4140 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
4141 mips_sw (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
4143 /* save the current IP */
4144 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4145 mips_load_const (code, mips_at, 0x01010101);
4146 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
4150 cfg->code_len = code - cfg->native_code;
4151 g_assert (cfg->code_len < cfg->code_size);
4166 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4169 int save_mode = SAVE_NONE;
4171 MonoMethod *method = cfg->method;
4172 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
4173 int save_offset = MIPS_STACK_PARAM_OFFSET;
4175 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
4177 offset = code - cfg->native_code;
4178 /* we need about 16 instructions */
4179 if (offset > (cfg->code_size - 16 * 4)) {
4180 cfg->code_size *= 2;
4181 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4182 code = cfg->native_code + offset;
4187 case MONO_TYPE_VOID:
4188 /* special case string .ctor icall */
4189 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
4190 save_mode = SAVE_ONE;
4192 save_mode = SAVE_NONE;
4196 save_mode = SAVE_TWO;
4200 save_mode = SAVE_FP;
4202 case MONO_TYPE_VALUETYPE:
4203 save_mode = SAVE_STRUCT;
4206 save_mode = SAVE_ONE;
4210 mips_addiu (code, mips_sp, mips_sp, -32);
4211 switch (save_mode) {
4213 mips_sw (code, mips_v0, mips_sp, save_offset);
4214 mips_sw (code, mips_v1, mips_sp, save_offset + 4);
4215 if (enable_arguments) {
4216 mips_move (code, mips_a1, mips_v0);
4217 mips_move (code, mips_a2, mips_v1);
4221 mips_sw (code, mips_v0, mips_sp, save_offset);
4222 if (enable_arguments) {
4223 mips_move (code, mips_a1, mips_v0);
4227 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
4228 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
4229 mips_lw (code, mips_a0, mips_sp, save_offset);
4230 mips_lw (code, mips_a1, mips_sp, save_offset+4);
4237 mips_load_const (code, mips_a0, cfg->method);
4238 mips_load_const (code, mips_t9, func);
4239 mips_jalr (code, mips_t9, mips_ra);
4242 switch (save_mode) {
4244 mips_lw (code, mips_v0, mips_sp, save_offset);
4245 mips_lw (code, mips_v1, mips_sp, save_offset + 4);
4248 mips_lw (code, mips_v0, mips_sp, save_offset);
4251 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
4258 mips_addiu (code, mips_sp, mips_sp, 32);
4265 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
4267 MonoMethod *method = cfg->method;
4269 int max_epilog_size = 16 + 20*4;
4270 guint32 iregs_to_restore;
4272 guint32 fregs_to_restore;
4276 if (cfg->method->save_lmf)
4277 max_epilog_size += 128;
4280 if (mono_jit_trace_calls != NULL)
4281 max_epilog_size += 50;
4283 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4284 max_epilog_size += 50;
4287 pos = code - cfg->native_code;
4288 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4289 cfg->code_size *= 2;
4290 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4291 mono_jit_stats.code_reallocs++;
4295 * Keep in sync with OP_JMP
4298 code = cfg->native_code + pos;
4300 code = cfg->native_code + cfg->code_len;
4302 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4303 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4305 pos = cfg->arch.iregs_offset;
4306 if (cfg->frame_reg != mips_sp) {
4307 mips_move (code, mips_sp, cfg->frame_reg);
4310 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
4312 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4314 if (iregs_to_restore) {
4315 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4316 if (iregs_to_restore & (1 << i)) {
4317 mips_lw (code, i, mips_sp, pos);
4318 pos += sizeof (gulong);
4325 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4327 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
4328 fregs_to_restore |= (fregs_to_restore << 1);
4330 if (fregs_to_restore) {
4331 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4332 if (fregs_to_restore & (1 << i)) {
4333 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4334 mips_lwc1 (code, i, mips_sp, pos);
4335 pos += sizeof (gulong);
4341 /* Unlink the LMF if necessary */
4342 if (method->save_lmf) {
4343 int lmf_offset = cfg->arch.lmf_offset;
4345 /* t0 = current_lmf->previous_lmf */
4346 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4348 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4349 /* (*lmf_addr) = previous_lmf */
4350 mips_sw (code, mips_temp, mips_t1, 0);
4354 /* Restore the fp */
4355 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
4357 /* Correct the stack pointer */
4358 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
4359 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
4360 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
4362 /* Caller will emit either return or tail-call sequence */
4364 cfg->code_len = code - cfg->native_code;
4366 g_assert (cfg->code_len < cfg->code_size);
4371 mono_arch_emit_epilog (MonoCompile *cfg)
4375 code = mono_arch_emit_epilog_sub (cfg, NULL);
4377 mips_jr (code, mips_ra);
4380 cfg->code_len = code - cfg->native_code;
4382 g_assert (cfg->code_len < cfg->code_size);
4385 /* remove once throw_exception_by_name is eliminated */
4387 exception_id_by_name (const char *name)
4389 if (strcmp (name, "IndexOutOfRangeException") == 0)
4390 return MONO_EXC_INDEX_OUT_OF_RANGE;
4391 if (strcmp (name, "OverflowException") == 0)
4392 return MONO_EXC_OVERFLOW;
4393 if (strcmp (name, "ArithmeticException") == 0)
4394 return MONO_EXC_ARITHMETIC;
4395 if (strcmp (name, "DivideByZeroException") == 0)
4396 return MONO_EXC_DIVIDE_BY_ZERO;
4397 if (strcmp (name, "InvalidCastException") == 0)
4398 return MONO_EXC_INVALID_CAST;
4399 if (strcmp (name, "NullReferenceException") == 0)
4400 return MONO_EXC_NULL_REF;
4401 if (strcmp (name, "ArrayTypeMismatchException") == 0)
4402 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4403 g_error ("Unknown intrinsic exception %s\n", name);
4408 mono_arch_emit_exceptions (MonoCompile *cfg)
4411 MonoJumpInfo *patch_info;
4414 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4415 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4416 int max_epilog_size = 50;
4418 /* count the number of exception infos */
4421 * make sure we have enough space for exceptions
4422 * 24 is the simulated call to throw_exception_by_name
4424 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4426 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4427 i = exception_id_by_name (patch_info->data.target);
4428 g_assert (i < MONO_EXC_INTRINS_NUM);
4429 if (!exc_throw_found [i]) {
4430 max_epilog_size += 12;
4431 exc_throw_found [i] = TRUE;
4437 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4438 cfg->code_size *= 2;
4439 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4440 mono_jit_stats.code_reallocs++;
4443 code = cfg->native_code + cfg->code_len;
4445 /* add code to raise exceptions */
4446 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4447 switch (patch_info->type) {
4448 case MONO_PATCH_INFO_EXC: {
4450 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
4452 i = exception_id_by_name (patch_info->data.target);
4453 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
4454 if (!exc_throw_pos [i]) {
4457 exc_throw_pos [i] = code;
4458 //g_print ("exc: writing stub at %p\n", code);
4459 mips_load_const (code, mips_a0, patch_info->data.target);
4460 addr = (guint32) mono_arch_get_throw_exception_by_name ();
4461 mips_load_const (code, mips_t9, addr);
4462 mips_jr (code, mips_t9);
4465 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
4467 /* Turn into a Relative patch, pointing at code stub */
4468 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
4469 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
4471 g_assert_not_reached();
4481 cfg->code_len = code - cfg->native_code;
4483 g_assert (cfg->code_len < cfg->code_size);
4488 * Thread local storage support
4491 setup_tls_access (void)
4494 //guint32 *ins, *code;
4496 if (tls_mode == TLS_MODE_FAILED)
4499 if (g_getenv ("MONO_NO_TLS")) {
4500 tls_mode = TLS_MODE_FAILED;
4504 if (tls_mode == TLS_MODE_DETECT) {
4506 tls_mode = TLS_MODE_FAILED;
4510 ins = (guint32*)pthread_getspecific;
4511 /* uncond branch to the real method */
4512 if ((*ins >> 26) == 18) {
4514 val = (*ins & ~3) << 6;
4518 ins = (guint32*)val;
4520 ins = (guint32*) ((char*)ins + val);
4523 code = &cmplwi_1023;
4524 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4526 ppc_li (code, ppc_r4, 0x48);
4529 if (*ins == cmplwi_1023) {
4530 int found_lwz_284 = 0;
4531 for (ptk = 0; ptk < 20; ++ptk) {
4533 if (!*ins || *ins == blr_ins)
4535 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4540 if (!found_lwz_284) {
4541 tls_mode = TLS_MODE_FAILED;
4544 tls_mode = TLS_MODE_LTHREADS;
4545 } else if (*ins == li_0x48) {
4547 /* uncond branch to the real method */
4548 if ((*ins >> 26) == 18) {
4550 val = (*ins & ~3) << 6;
4554 ins = (guint32*)val;
4556 ins = (guint32*) ((char*)ins + val);
4559 ppc_li (code, ppc_r0, 0x7FF2);
4560 if (ins [1] == val) {
4561 /* Darwin on G4, implement */
4562 tls_mode = TLS_MODE_FAILED;
4566 ppc_mfspr (code, ppc_r3, 104);
4567 if (ins [1] != val) {
4568 tls_mode = TLS_MODE_FAILED;
4571 tls_mode = TLS_MODE_DARWIN_G5;
4574 tls_mode = TLS_MODE_FAILED;
4578 tls_mode = TLS_MODE_FAILED;
4583 if (monodomain_key == -1) {
4584 ptk = mono_domain_get_tls_key ();
4586 ptk = mono_pthread_key_for_tls (ptk);
4588 monodomain_key = ptk;
4592 if (lmf_pthread_key == -1) {
4593 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4595 /*g_print ("MonoLMF at: %d\n", ptk);*/
4596 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4597 init_tls_failed = 1;
4600 lmf_pthread_key = ptk;
4603 if (monothread_key == -1) {
4604 ptk = mono_thread_get_tls_key ();
4606 ptk = mono_pthread_key_for_tls (ptk);
4608 monothread_key = ptk;
4609 /*g_print ("thread inited: %d\n", ptk);*/
4612 /*g_print ("thread not inited yet %d\n", ptk);*/
4618 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4620 setup_tls_access ();
4624 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4629 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4631 int this_dreg = mips_a0;
4634 this_dreg = mips_a1;
4636 /* add the this argument */
4637 if (this_reg != -1) {
4639 MONO_INST_NEW (cfg, this, OP_MOVE);
4640 this->type = this_type;
4641 this->sreg1 = this_reg;
4642 this->dreg = mono_alloc_ireg (cfg);
4643 mono_bblock_add_inst (cfg->cbb, this);
4644 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4649 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4650 vtarg->type = STACK_MP;
4651 vtarg->sreg1 = vt_reg;
4652 vtarg->dreg = mono_alloc_ireg (cfg);
4653 mono_bblock_add_inst (cfg->cbb, vtarg);
4654 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
4659 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4661 MonoInst *ins = NULL;
4667 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4673 mono_arch_print_tree (MonoInst *tree, int arity)
4678 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4682 setup_tls_access ();
4683 if (monodomain_key == -1)
4686 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4687 ins->inst_offset = monodomain_key;
4692 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4696 setup_tls_access ();
4697 if (monothread_key == -1)
4700 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4701 ins->inst_offset = monothread_key;
4706 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4708 /* FIXME: implement */
4709 g_assert_not_reached ();
4712 #ifdef MONO_ARCH_HAVE_IMT
4716 #define JUMP_IMM_SIZE 12
4717 #define JUMP_IMM32_SIZE 16
4718 #define ENABLE_WRONG_METHOD_CHECK 0
4721 * LOCKING: called with the domain lock held
4724 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4725 gpointer fail_tramp)
4731 guint8 *code, *start;
4733 for (i = 0; i < count; ++i) {
4734 MonoIMTCheckItem *item = imt_entries [i];
4735 if (item->is_equals) {
4736 if (item->check_target_idx) {
4737 if (!item->compare_done)
4738 item->chunk_size += CMP_SIZE;
4740 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
4742 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4745 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
4747 item->chunk_size += JUMP_IMM_SIZE;
4748 #if ENABLE_WRONG_METHOD_CHECK
4749 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4754 item->chunk_size += CMP_SIZE + BR_SIZE;
4755 imt_entries [item->check_target_idx]->compare_done = TRUE;
4757 size += item->chunk_size;
4760 code = mono_method_alloc_generic_virtual_thunk (domain, size);
4762 /* the initial load of the vtable address */
4764 code = mono_code_manager_reserve (domain->code_mp, size);
4768 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4769 for (i = 0; i < count; ++i) {
4770 MonoIMTCheckItem *item = imt_entries [i];
4771 item->code_target = code;
4772 if (item->is_equals) {
4773 if (item->check_target_idx) {
4774 if (!item->compare_done) {
4775 ppc_load (code, ppc_r0, (guint32)item->key);
4776 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4778 item->jmp_code = code;
4779 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4781 ppc_load (code, ppc_r0, item->value.target_code);
4783 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4784 ppc_mtctr (code, ppc_r0);
4785 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4788 ppc_load (code, ppc_r0, (guint32)item->key);
4789 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4790 item->jmp_code = code;
4791 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4792 ppc_load (code, ppc_r0, item->value.target_code);
4793 ppc_mtctr (code, ppc_r0);
4794 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4795 ppc_patch (item->jmp_code, code);
4796 ppc_load (code, ppc_r0, fail_tramp);
4797 ppc_mtctr (code, ppc_r0);
4798 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4799 item->jmp_code = NULL;
4801 /* enable the commented code to assert on wrong method */
4802 #if ENABLE_WRONG_METHOD_CHECK
4803 ppc_load (code, ppc_r0, (guint32)item->key);
4804 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4805 item->jmp_code = code;
4806 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4808 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4809 ppc_mtctr (code, ppc_r0);
4810 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4811 #if ENABLE_WRONG_METHOD_CHECK
4812 ppc_patch (item->jmp_code, code);
4814 item->jmp_code = NULL;
4819 ppc_load (code, ppc_r0, (guint32)item->key);
4820 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4821 item->jmp_code = code;
4822 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4825 /* patch the branches to get to the target items */
4826 for (i = 0; i < count; ++i) {
4827 MonoIMTCheckItem *item = imt_entries [i];
4828 if (item->jmp_code) {
4829 if (item->check_target_idx) {
4830 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4836 mono_stats.imt_thunks_size += code - start;
4837 g_assert (code - start <= size);
4838 mono_arch_flush_icache (start, size);
4844 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4846 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4850 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4852 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4857 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
4860 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];