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>
20 #include <mono/utils/mono-mmap.h>
22 #include <mono/arch/mips/mips-codegen.h>
24 #include "mini-mips.h"
29 #define SAVE_FP_REGS 0
30 #define SAVE_ALL_REGS 0
31 #define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
34 #define ALWAYS_USE_FP 1
35 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
37 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
38 #define USE_MUL 1 /* use mul instead of mult/mflo for multiply */
40 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
41 #define mips_call(c,D,v) do { \
42 guint32 _target = (guint32)(v); \
43 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
44 mips_load_const (c, D, _target); \
45 mips_jalr (c, D, mips_ra); \
48 mips_jumpl (c, _target >> 2); \
60 /* This mutex protects architecture specific caches */
61 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
62 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
63 static CRITICAL_SECTION mini_arch_mutex;
65 int mono_exc_esp_offset = 0;
66 static int tls_mode = TLS_MODE_DETECT;
67 static int lmf_pthread_key = -1;
68 static int monothread_key = -1;
69 static int monodomain_key = -1;
71 /* Whenever the host is little-endian */
72 static int little_endian;
73 /* Index of ms word/register */
74 static int ls_word_idx;
75 /* Index of ls word/register */
76 static int ms_word_idx;
77 /* Same for offsets */
78 static int ls_word_offset;
79 static int ms_word_offset;
82 * The code generated for sequence points reads from this location, which is
83 * made read-only when single stepping is enabled.
85 static gpointer ss_trigger_page;
87 /* Enabled breakpoints read from this trigger page */
88 static gpointer bp_trigger_page;
91 #define DEBUG(a) if (cfg->verbose_level > 1) a
97 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
99 code = mips_emit_exc_by_name (code, exc_name); \
100 cfg->bb_exit->max_offset += 16; \
104 #define emit_linuxthreads_tls(code,dreg,key) do {\
106 off1 = offsets_from_pthread_key ((key), &off2); \
107 g_assert_not_reached (); \
108 ppc_lwz ((code), (dreg), off1, ppc_r2); \
109 ppc_lwz ((code), (dreg), off2, (dreg)); \
113 #define emit_tls_access(code,dreg,key) do { \
114 switch (tls_mode) { \
115 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
116 default: g_assert_not_reached (); \
120 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
122 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
123 inst->type = STACK_R8; \
125 inst->inst_p0 = (void*)(addr); \
126 mono_bblock_add_inst (cfg->cbb, inst); \
129 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
130 || ((ins)->opcode == OP_ICOMPARE) \
131 || ((ins)->opcode == OP_LCOMPARE)))
132 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
133 || ((ins)->opcode == OP_ICOMPARE_IMM) \
134 || ((ins)->opcode == OP_LCOMPARE_IMM)))
136 #define INS_REWRITE(ins, op, _s1, _s2) do { \
139 ins->opcode = (op); \
144 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
146 ins->opcode = (op); \
148 ins->inst_imm = (_imm); \
152 typedef struct InstList InstList;
170 guint16 vtsize; /* in param area */
172 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
173 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
182 gboolean vtype_retaddr;
191 void patch_lui_addiu(guint32 *ip, guint32 val);
192 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
193 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
194 void mips_adjust_stackframe(MonoCompile *cfg);
195 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
196 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
199 /* Not defined in asm/cachectl.h */
200 int cacheflush(char *addr, int nbytes, int cache);
203 mono_arch_flush_icache (guint8 *code, gint size)
205 /* Linux/MIPS specific */
206 cacheflush ((char*)code, size, BCACHE);
210 mono_arch_flush_register_windows (void)
215 mono_arch_is_inst_imm (gint64 imm)
221 mips_emit_exc_by_name(guint8 *code, const char *name)
224 MonoClass *exc_class;
226 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
227 g_assert (exc_class);
229 mips_load_const (code, mips_a0, exc_class->type_token);
230 addr = mono_get_throw_corlib_exception ();
231 mips_call (code, mips_t9, addr);
237 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
239 if (mips_is_imm16 (v))
240 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
242 #if SIZEOF_REGISTER == 8
244 /* v is not a sign-extended 32-bit value */
245 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
246 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
247 mips_dsll (code, dreg, dreg, 16);
248 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
249 mips_dsll (code, dreg, dreg, 16);
250 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
254 if (((guint32)v) & (1 << 15)) {
255 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
258 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
260 if (((guint32)v) & 0xffff)
261 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
267 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
270 if (cfg->arch.long_branch) {
273 /* Invert test and emit branch around jump */
276 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
280 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
284 mips_bltz (code, ins->sreg1, br_offset);
288 mips_blez (code, ins->sreg1, br_offset);
292 mips_bgtz (code, ins->sreg1, br_offset);
296 mips_bgez (code, ins->sreg1, br_offset);
300 g_assert_not_reached ();
302 mono_add_patch_info (cfg, code - cfg->native_code,
303 MONO_PATCH_INFO_BB, ins->inst_true_bb);
304 mips_lui (code, mips_at, mips_zero, 0);
305 mips_addiu (code, mips_at, mips_at, 0);
306 mips_jr (code, mips_at);
310 mono_add_patch_info (cfg, code - cfg->native_code,
311 MONO_PATCH_INFO_BB, ins->inst_true_bb);
314 mips_beq (code, ins->sreg1, ins->sreg2, 0);
318 mips_bne (code, ins->sreg1, ins->sreg2, 0);
322 mips_bgez (code, ins->sreg1, 0);
326 mips_bgtz (code, ins->sreg1, 0);
330 mips_blez (code, ins->sreg1, 0);
334 mips_bltz (code, ins->sreg1, 0);
338 g_assert_not_reached ();
344 /* XXX - big-endian dependent? */
346 patch_lui_addiu(guint32 *ip, guint32 val)
348 guint16 *__lui_addiu = (guint16*)(void *)(ip);
351 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
352 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
355 if (((guint32)(val)) & (1 << 15))
356 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
358 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
359 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
360 mono_arch_flush_icache ((guint8 *)ip, 8);
365 mips_patch (guint32 *code, guint32 target)
368 guint32 op = ins >> 26;
369 guint32 diff, offset;
371 g_assert (trap_target != target);
372 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
374 case 0x00: /* jr ra */
375 if (ins == 0x3e00008)
377 g_assert_not_reached ();
381 g_assert (!(target & 0x03));
382 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
383 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
385 mono_arch_flush_icache ((guint8 *)code, 4);
387 case 0x01: /* BLTZ */
390 case 0x06: /* BLEZ */
391 case 0x07: /* BGTZ */
392 case 0x11: /* bc1t */
393 diff = target - (guint32)(code + 1);
394 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
395 g_assert (!(diff & 0x03));
396 offset = ((gint32)diff) >> 2;
397 g_assert (((int)offset) == ((int)(short)offset));
398 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
400 mono_arch_flush_icache ((guint8 *)code, 4);
402 case 0x0f: /* LUI / ADDIU pair */
403 g_assert ((code[1] >> 26) == 0x9);
404 patch_lui_addiu (code, target);
405 mono_arch_flush_icache ((guint8 *)code, 8);
409 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
410 g_assert_not_reached ();
416 offsets_from_pthread_key (guint32 key, int *offset2)
420 *offset2 = idx2 * sizeof (gpointer);
421 return 284 + idx1 * sizeof (gpointer);
426 mono_arch_regname (int reg) {
427 #if _MIPS_SIM == _ABIO32
428 static const char * rnames[] = {
429 "zero", "at", "v0", "v1",
430 "a0", "a1", "a2", "a3",
431 "t0", "t1", "t2", "t3",
432 "t4", "t5", "t6", "t7",
433 "s0", "s1", "s2", "s3",
434 "s4", "s5", "s6", "s7",
435 "t8", "t9", "k0", "k1",
436 "gp", "sp", "fp", "ra"
438 #elif _MIPS_SIM == _ABIN32
439 static const char * rnames[] = {
440 "zero", "at", "v0", "v1",
441 "a0", "a1", "a2", "a3",
442 "a4", "a5", "a6", "a7",
443 "t0", "t1", "t2", "t3",
444 "s0", "s1", "s2", "s3",
445 "s4", "s5", "s6", "s7",
446 "t8", "t9", "k0", "k1",
447 "gp", "sp", "fp", "ra"
450 if (reg >= 0 && reg < 32)
456 mono_arch_fregname (int reg) {
457 static const char * rnames[] = {
458 "f0", "f1", "f2", "f3",
459 "f4", "f5", "f6", "f7",
460 "f8", "f9", "f10", "f11",
461 "f12", "f13", "f14", "f15",
462 "f16", "f17", "f18", "f19",
463 "f20", "f21", "f22", "f23",
464 "f24", "f25", "f26", "f27",
465 "f28", "f29", "f30", "f31"
467 if (reg >= 0 && reg < 32)
472 /* this function overwrites at */
474 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
476 /* XXX write a loop, not an unrolled loop */
478 mips_lw (code, mips_at, sreg, soffset);
479 mips_sw (code, mips_at, dreg, doffset);
488 * mono_arch_get_argument_info:
489 * @csig: a method signature
490 * @param_count: the number of parameters to consider
491 * @arg_info: an array to store the result infos
493 * Gathers information on parameters such as size, alignment and
494 * padding. arg_info should be large enought to hold param_count + 1 entries.
496 * Returns the size of the activation frame.
499 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
501 int k, frame_size = 0;
502 guint32 size, align, pad;
505 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
506 frame_size += sizeof (gpointer);
510 arg_info [0].offset = offset;
513 frame_size += sizeof (gpointer);
517 arg_info [0].size = frame_size;
519 for (k = 0; k < param_count; k++) {
520 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
522 /* ignore alignment for now */
525 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
526 arg_info [k].pad = pad;
528 arg_info [k + 1].pad = 0;
529 arg_info [k + 1].size = size;
531 arg_info [k + 1].offset = offset;
535 align = MONO_ARCH_FRAME_ALIGNMENT;
536 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
537 arg_info [k].pad = pad;
544 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
547 return (gpointer)regs [mips_a0];
551 * Initialize the cpu to execute managed code.
554 mono_arch_cpu_init (void)
556 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
565 ls_word_offset = ls_word_idx * 4;
566 ms_word_offset = ms_word_idx * 4;
570 * Initialize architecture specific code.
573 mono_arch_init (void)
575 InitializeCriticalSection (&mini_arch_mutex);
577 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
578 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
579 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
583 * Cleanup architecture specific code.
586 mono_arch_cleanup (void)
588 DeleteCriticalSection (&mini_arch_mutex);
592 * This function returns the optimizations supported on this cpu.
595 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
599 /* no mips-specific optimizations yet */
605 is_regsize_var (MonoType *t) {
608 t = mono_type_get_underlying_type (t);
612 #if (SIZEOF_REGISTER == 8)
619 case MONO_TYPE_FNPTR:
621 case MONO_TYPE_OBJECT:
622 case MONO_TYPE_STRING:
623 case MONO_TYPE_CLASS:
624 case MONO_TYPE_SZARRAY:
625 case MONO_TYPE_ARRAY:
627 case MONO_TYPE_GENERICINST:
628 if (!mono_type_generic_inst_is_valuetype (t))
631 case MONO_TYPE_VALUETYPE:
638 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
643 for (i = 0; i < cfg->num_varinfo; i++) {
644 MonoInst *ins = cfg->varinfo [i];
645 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
648 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
651 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
654 /* we can only allocate 32 bit values */
655 if (is_regsize_var (ins->inst_vtype)) {
656 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
657 g_assert (i == vmv->idx);
658 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
666 mono_arch_get_global_int_regs (MonoCompile *cfg)
670 regs = g_list_prepend (regs, (gpointer)mips_s0);
671 regs = g_list_prepend (regs, (gpointer)mips_s1);
672 regs = g_list_prepend (regs, (gpointer)mips_s2);
673 regs = g_list_prepend (regs, (gpointer)mips_s3);
674 regs = g_list_prepend (regs, (gpointer)mips_s4);
675 //regs = g_list_prepend (regs, (gpointer)mips_s5);
676 regs = g_list_prepend (regs, (gpointer)mips_s6);
677 regs = g_list_prepend (regs, (gpointer)mips_s7);
683 * mono_arch_regalloc_cost:
685 * Return the cost, in number of memory references, of the action of
686 * allocating the variable VMV into a register during global register
690 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
697 args_onto_stack (CallInfo *info)
699 g_assert (!info->on_stack);
700 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
701 info->on_stack = TRUE;
702 info->stack_size = MIPS_STACK_PARAM_OFFSET;
705 #if _MIPS_SIM == _ABIO32
707 * O32 calling convention version
711 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
712 /* First, see if we need to drop onto the stack */
713 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
714 args_onto_stack (info);
716 /* Now, place the argument */
717 if (info->on_stack) {
718 ainfo->regtype = RegTypeBase;
719 ainfo->reg = mips_sp; /* in the caller */
720 ainfo->offset = info->stack_size;
723 ainfo->regtype = RegTypeGeneral;
724 ainfo->reg = info->gr;
726 info->gr_passed = TRUE;
728 info->stack_size += 4;
732 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
733 /* First, see if we need to drop onto the stack */
734 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
735 args_onto_stack (info);
737 /* Now, place the argument */
738 if (info->on_stack) {
739 g_assert (info->stack_size % 4 == 0);
740 info->stack_size += (info->stack_size % 8);
742 ainfo->regtype = RegTypeBase;
743 ainfo->reg = mips_sp; /* in the caller */
744 ainfo->offset = info->stack_size;
747 // info->gr must be a0 or a2
748 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
749 g_assert(info->gr <= MIPS_LAST_ARG_REG);
751 ainfo->regtype = RegTypeGeneral;
752 ainfo->reg = info->gr;
754 info->gr_passed = TRUE;
756 info->stack_size += 8;
760 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
761 /* First, see if we need to drop onto the stack */
762 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
763 args_onto_stack (info);
765 /* Now, place the argument */
766 if (info->on_stack) {
767 ainfo->regtype = RegTypeBase;
768 ainfo->reg = mips_sp; /* in the caller */
769 ainfo->offset = info->stack_size;
772 /* Only use FP regs for args if no int args passed yet */
773 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
774 ainfo->regtype = RegTypeFP;
775 ainfo->reg = info->fr;
776 /* Even though it's a single-precision float, it takes up two FP regs */
778 /* FP and GP slots do not overlap */
782 /* Passing single-precision float arg in a GP register
783 * such as: func (0, 1.0, 2, 3);
784 * In this case, only one 'gr' register is consumed.
786 ainfo->regtype = RegTypeGeneral;
787 ainfo->reg = info->gr;
790 info->gr_passed = TRUE;
793 info->stack_size += 4;
797 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
798 /* First, see if we need to drop onto the stack */
799 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
800 args_onto_stack (info);
802 /* Now, place the argument */
803 if (info->on_stack) {
804 g_assert(info->stack_size % 4 == 0);
805 info->stack_size += (info->stack_size % 8);
807 ainfo->regtype = RegTypeBase;
808 ainfo->reg = mips_sp; /* in the caller */
809 ainfo->offset = info->stack_size;
812 /* Only use FP regs for args if no int args passed yet */
813 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
814 ainfo->regtype = RegTypeFP;
815 ainfo->reg = info->fr;
817 /* FP and GP slots do not overlap */
821 // info->gr must be a0 or a2
822 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
823 g_assert(info->gr <= MIPS_LAST_ARG_REG);
825 ainfo->regtype = RegTypeGeneral;
826 ainfo->reg = info->gr;
828 info->gr_passed = TRUE;
831 info->stack_size += 8;
833 #elif _MIPS_SIM == _ABIN32
835 * N32 calling convention version
839 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
840 /* First, see if we need to drop onto the stack */
841 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
842 args_onto_stack (info);
844 /* Now, place the argument */
845 if (info->on_stack) {
846 ainfo->regtype = RegTypeBase;
847 ainfo->reg = mips_sp; /* in the caller */
848 ainfo->offset = info->stack_size;
849 info->stack_size += SIZEOF_REGISTER;
852 ainfo->regtype = RegTypeGeneral;
853 ainfo->reg = info->gr;
855 info->gr_passed = TRUE;
860 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
861 /* First, see if we need to drop onto the stack */
862 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
863 args_onto_stack (info);
865 /* Now, place the argument */
866 if (info->on_stack) {
867 g_assert (info->stack_size % 4 == 0);
868 info->stack_size += (info->stack_size % 8);
870 ainfo->regtype = RegTypeBase;
871 ainfo->reg = mips_sp; /* in the caller */
872 ainfo->offset = info->stack_size;
873 info->stack_size += SIZEOF_REGISTER;
876 g_assert (info->gr <= MIPS_LAST_ARG_REG);
878 ainfo->regtype = RegTypeGeneral;
879 ainfo->reg = info->gr;
881 info->gr_passed = TRUE;
886 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
887 /* First, see if we need to drop onto the stack */
888 if (!info->on_stack) {
889 if (info->gr > MIPS_LAST_ARG_REG)
890 args_onto_stack (info);
891 else if (info->fr > MIPS_LAST_FPARG_REG)
892 args_onto_stack (info);
895 /* Now, place the argument */
896 if (info->on_stack) {
897 ainfo->regtype = RegTypeBase;
898 ainfo->reg = mips_sp; /* in the caller */
899 ainfo->offset = info->stack_size;
900 info->stack_size += FREG_SIZE;
903 ainfo->regtype = RegTypeFP;
904 ainfo->reg = info->fr;
906 /* FP and GP slots do not overlap */
912 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
913 /* First, see if we need to drop onto the stack */
914 if (!info->on_stack) {
915 if (info->gr > MIPS_LAST_ARG_REG)
916 args_onto_stack (info);
917 else if (info->fr > MIPS_LAST_FPARG_REG)
918 args_onto_stack (info);
921 /* Now, place the argument */
922 if (info->on_stack) {
923 g_assert(info->stack_size % 4 == 0);
924 info->stack_size += (info->stack_size % 8);
926 ainfo->regtype = RegTypeBase;
927 ainfo->reg = mips_sp; /* in the caller */
928 ainfo->offset = info->stack_size;
929 info->stack_size += FREG_SIZE;
932 ainfo->regtype = RegTypeFP;
933 ainfo->reg = info->fr;
935 /* FP and GP slots do not overlap */
942 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
945 int n = sig->hasthis + sig->param_count;
947 MonoType* simpletype;
948 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
950 cinfo->fr = MIPS_FIRST_FPARG_REG;
951 cinfo->gr = MIPS_FIRST_ARG_REG;
952 cinfo->stack_size = 0;
954 DEBUG(printf("calculate_sizes\n"));
956 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
960 /* handle returning a struct */
961 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
962 cinfo->struct_ret = cinfo->gr;
963 add_int32_arg (cinfo, &cinfo->ret);
967 add_int32_arg (cinfo, cinfo->args + n);
972 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
973 * the first argument, allowing 'this' to be always passed in the first arg reg.
974 * Also do this if the first argument is a reference type, since virtual calls
975 * are sometimes made using calli without sig->hasthis set, like in the delegate
978 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (NULL, sig->params [0]))))) {
980 add_int32_arg (cinfo, cinfo->args + n);
983 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
987 add_int32_arg (cinfo, &cinfo->ret);
988 cinfo->struct_ret = cinfo->ret.reg;
992 add_int32_arg (cinfo, cinfo->args + n);
996 if (cinfo->vtype_retaddr) {
997 add_int32_arg (cinfo, &cinfo->ret);
998 cinfo->struct_ret = cinfo->ret.reg;
1003 DEBUG(printf("params: %d\n", sig->param_count));
1004 for (i = pstart; i < sig->param_count; ++i) {
1005 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1006 /* Prevent implicit arguments and sig_cookie from
1007 being passed in registers */
1008 args_onto_stack (cinfo);
1009 /* Emit the signature cookie just before the implicit arguments */
1010 add_int32_arg (cinfo, &cinfo->sig_cookie);
1012 DEBUG(printf("param %d: ", i));
1013 if (sig->params [i]->byref) {
1014 DEBUG(printf("byref\n"));
1015 add_int32_arg (cinfo, &cinfo->args[n]);
1019 simpletype = mono_type_get_underlying_type (sig->params [i]);
1020 switch (simpletype->type) {
1021 case MONO_TYPE_BOOLEAN:
1024 DEBUG(printf("1 byte\n"));
1025 cinfo->args [n].size = 1;
1026 add_int32_arg (cinfo, &cinfo->args[n]);
1029 case MONO_TYPE_CHAR:
1032 DEBUG(printf("2 bytes\n"));
1033 cinfo->args [n].size = 2;
1034 add_int32_arg (cinfo, &cinfo->args[n]);
1039 DEBUG(printf("4 bytes\n"));
1040 cinfo->args [n].size = 4;
1041 add_int32_arg (cinfo, &cinfo->args[n]);
1047 case MONO_TYPE_FNPTR:
1048 case MONO_TYPE_CLASS:
1049 case MONO_TYPE_OBJECT:
1050 case MONO_TYPE_STRING:
1051 case MONO_TYPE_SZARRAY:
1052 case MONO_TYPE_ARRAY:
1053 cinfo->args [n].size = sizeof (gpointer);
1054 add_int32_arg (cinfo, &cinfo->args[n]);
1057 case MONO_TYPE_GENERICINST:
1058 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1059 cinfo->args [n].size = sizeof (gpointer);
1060 add_int32_arg (cinfo, &cinfo->args[n]);
1065 case MONO_TYPE_VALUETYPE: {
1068 int has_offset = FALSE;
1070 gint size, alignment;
1073 klass = mono_class_from_mono_type (sig->params [i]);
1075 size = mono_class_native_size (klass, NULL);
1077 size = mono_class_value_size (klass, NULL);
1078 alignment = mono_class_min_align (klass);
1079 #if MIPS_PASS_STRUCTS_BY_VALUE
1080 /* Need to do alignment if struct contains long or double */
1081 if (alignment > 4) {
1082 /* Drop onto stack *before* looking at
1083 stack_size, if required. */
1084 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1085 args_onto_stack (cinfo);
1086 if (cinfo->stack_size & (alignment - 1)) {
1087 add_int32_arg (cinfo, &dummy_arg);
1089 g_assert (!(cinfo->stack_size & (alignment - 1)));
1093 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1094 mono_class_native_size (sig->params [i]->data.klass, NULL),
1095 cinfo->stack_size, alignment);
1097 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1098 g_assert (cinfo->args [n].size == 0);
1099 g_assert (cinfo->args [n].vtsize == 0);
1100 for (j = 0; j < nwords; ++j) {
1102 add_int32_arg (cinfo, &cinfo->args [n]);
1103 if (cinfo->on_stack)
1106 add_int32_arg (cinfo, &dummy_arg);
1107 if (!has_offset && cinfo->on_stack) {
1108 cinfo->args [n].offset = dummy_arg.offset;
1112 if (cinfo->on_stack)
1113 cinfo->args [n].vtsize += 1;
1115 cinfo->args [n].size += 1;
1117 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1118 cinfo->args [n].regtype = RegTypeStructByVal;
1120 add_int32_arg (cinfo, &cinfo->args[n]);
1121 cinfo->args [n].regtype = RegTypeStructByAddr;
1126 case MONO_TYPE_TYPEDBYREF: {
1127 /* keep in sync or merge with the valuetype case */
1128 #if MIPS_PASS_STRUCTS_BY_VALUE
1130 int size = sizeof (MonoTypedRef);
1131 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1132 cinfo->args [n].regtype = RegTypeStructByVal;
1133 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
1134 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
1135 int n_in_regs = rest >= nwords? nwords: rest;
1136 cinfo->args [n].size = n_in_regs;
1137 cinfo->args [n].vtsize = nwords - n_in_regs;
1138 cinfo->args [n].reg = cinfo->gr;
1139 cinfo->gr += n_in_regs;
1140 cinfo->gr_passed = TRUE;
1142 cinfo->args [n].size = 0;
1143 cinfo->args [n].vtsize = nwords;
1145 if (cinfo->args [n].vtsize > 0) {
1146 if (!cinfo->on_stack)
1147 args_onto_stack (cinfo);
1148 g_assert(cinfo->on_stack);
1149 cinfo->args [n].offset = cinfo->stack_size;
1150 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
1151 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
1155 add_int32_arg (cinfo, &cinfo->args[n]);
1156 cinfo->args [n].regtype = RegTypeStructByAddr;
1163 DEBUG(printf("8 bytes\n"));
1164 cinfo->args [n].size = 8;
1165 add_int64_arg (cinfo, &cinfo->args[n]);
1169 DEBUG(printf("R4\n"));
1170 cinfo->args [n].size = 4;
1171 add_float32_arg (cinfo, &cinfo->args[n]);
1175 DEBUG(printf("R8\n"));
1176 cinfo->args [n].size = 8;
1177 add_float64_arg (cinfo, &cinfo->args[n]);
1181 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1186 simpletype = mono_type_get_underlying_type (sig->ret);
1187 switch (simpletype->type) {
1188 case MONO_TYPE_BOOLEAN:
1193 case MONO_TYPE_CHAR:
1199 case MONO_TYPE_FNPTR:
1200 case MONO_TYPE_CLASS:
1201 case MONO_TYPE_OBJECT:
1202 case MONO_TYPE_SZARRAY:
1203 case MONO_TYPE_ARRAY:
1204 case MONO_TYPE_STRING:
1205 cinfo->ret.reg = mips_v0;
1209 cinfo->ret.reg = mips_v0;
1213 cinfo->ret.reg = mips_f0;
1214 cinfo->ret.regtype = RegTypeFP;
1216 case MONO_TYPE_GENERICINST:
1217 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1218 cinfo->ret.reg = mips_v0;
1222 case MONO_TYPE_VALUETYPE:
1224 case MONO_TYPE_TYPEDBYREF:
1225 case MONO_TYPE_VOID:
1228 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1232 /* align stack size to 16 */
1233 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1235 cinfo->stack_usage = cinfo->stack_size;
1241 * Set var information according to the calling convention. mips version.
1242 * The locals var stuff should most likely be split in another method.
1245 mono_arch_allocate_vars (MonoCompile *cfg)
1247 MonoMethodSignature *sig;
1248 MonoMethodHeader *header;
1250 int i, offset, size, align, curinst;
1251 int frame_reg = mips_sp;
1252 guint32 iregs_to_save = 0;
1254 guint32 fregs_to_restore;
1257 /* spill down, we'll fix it in a separate pass */
1258 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1260 /* allow room for the vararg method args: void* and long/double */
1261 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1262 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1264 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1265 * call convs needs to be handled this way.
1267 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1268 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1270 /* gtk-sharp and other broken code will dllimport vararg functions even with
1271 * non-varargs signatures. Since there is little hope people will get this right
1272 * we assume they won't.
1274 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1275 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1277 /* a0-a3 always present */
1278 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1280 header = cfg->header;
1282 sig = mono_method_signature (cfg->method);
1285 * We use the frame register also for any method that has
1286 * exception clauses. This way, when the handlers are called,
1287 * the code will reference local variables using the frame reg instead of
1288 * the stack pointer: if we had to restore the stack pointer, we'd
1289 * corrupt the method frames that are already on the stack (since
1290 * filters get called before stack unwinding happens) when the filter
1291 * code would call any method (this also applies to finally etc.).
1294 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
1295 frame_reg = mips_fp;
1296 cfg->frame_reg = frame_reg;
1297 if (frame_reg != mips_sp) {
1298 cfg->used_int_regs |= 1 << frame_reg;
1303 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1304 /* FIXME: handle long and FP values */
1305 switch (mono_type_get_underlying_type (sig->ret)->type) {
1306 case MONO_TYPE_VOID:
1310 cfg->ret->opcode = OP_REGVAR;
1311 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1314 cfg->ret->opcode = OP_REGVAR;
1315 cfg->ret->inst_c0 = mips_v0;
1319 /* Space for outgoing parameters, including a0-a3 */
1320 offset += cfg->param_area;
1322 /* allow room to save the return value (if it's a struct) */
1323 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1326 if (sig->call_convention == MONO_CALL_VARARG) {
1327 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1330 /* Now handle the local variables */
1332 curinst = cfg->locals_start;
1333 for (i = curinst; i < cfg->num_varinfo; ++i) {
1334 inst = cfg->varinfo [i];
1335 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1338 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1339 * pinvoke wrappers when they call functions returning structure
1341 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1342 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1344 size = mono_type_size (inst->inst_vtype, &align);
1346 offset += align - 1;
1347 offset &= ~(align - 1);
1348 inst->inst_offset = offset;
1349 inst->opcode = OP_REGOFFSET;
1350 inst->inst_basereg = frame_reg;
1352 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1355 /* Space for LMF (if needed) */
1357 if (cfg->method->save_lmf) {
1358 /* align the offset to 16 bytes */
1359 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1360 cfg->arch.lmf_offset = offset;
1361 offset += sizeof (MonoLMF);
1365 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1366 * args or return vals. Extra stack space avoids this in a lot of cases.
1368 offset += EXTRA_STACK_SPACE;
1369 offset += SIZEOF_REGISTER - 1;
1370 offset &= ~(SIZEOF_REGISTER - 1);
1372 /* Space for saved registers */
1373 cfg->arch.iregs_offset = offset;
1375 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1377 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1379 if (iregs_to_save) {
1380 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1381 if (iregs_to_save & (1 << i)) {
1382 offset += SIZEOF_REGISTER;
1387 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1388 * args or return vals. Extra stack space avoids this in a lot of cases.
1390 offset += EXTRA_STACK_SPACE;
1392 /* saved float registers */
1394 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1395 if (fregs_to_restore) {
1396 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1397 if (fregs_to_restore & (1 << i)) {
1398 offset += sizeof(double);
1404 #if _MIPS_SIM == _ABIO32
1405 /* Now add space for saving the ra */
1406 offset += SIZEOF_VOID_P;
1409 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1410 cfg->stack_offset = offset;
1411 cfg->arch.local_alloc_offset = cfg->stack_offset;
1415 * Now allocate stack slots for the int arg regs (a0 - a3)
1416 * On MIPS o32, these are just above the incoming stack pointer
1417 * Even if the arg has been assigned to a regvar, it gets a stack slot
1420 /* Return struct-by-value results in a hidden first argument */
1421 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1422 cfg->vret_addr->opcode = OP_REGOFFSET;
1423 cfg->vret_addr->inst_c0 = mips_a0;
1424 cfg->vret_addr->inst_offset = offset;
1425 cfg->vret_addr->inst_basereg = frame_reg;
1426 offset += SIZEOF_REGISTER;
1429 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1430 inst = cfg->args [i];
1431 if (inst->opcode != OP_REGVAR) {
1434 if (sig->hasthis && (i == 0))
1435 arg_type = &mono_defaults.object_class->byval_arg;
1437 arg_type = sig->params [i - sig->hasthis];
1439 inst->opcode = OP_REGOFFSET;
1440 size = mono_type_size (arg_type, &align);
1442 if (size < SIZEOF_REGISTER) {
1443 size = SIZEOF_REGISTER;
1444 align = SIZEOF_REGISTER;
1446 inst->inst_basereg = frame_reg;
1447 offset = (offset + align - 1) & ~(align - 1);
1448 inst->inst_offset = offset;
1450 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1451 cfg->sig_cookie += size;
1452 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1455 #if _MIPS_SIM == _ABIO32
1456 /* o32: Even a0-a3 get stack slots */
1457 size = SIZEOF_REGISTER;
1458 align = SIZEOF_REGISTER;
1459 inst->inst_basereg = frame_reg;
1460 offset = (offset + align - 1) & ~(align - 1);
1461 inst->inst_offset = offset;
1463 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1464 cfg->sig_cookie += size;
1465 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1469 #if _MIPS_SIM == _ABIN32
1470 /* Now add space for saving the ra */
1471 offset += SIZEOF_VOID_P;
1474 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1475 cfg->stack_offset = offset;
1476 cfg->arch.local_alloc_offset = cfg->stack_offset;
1481 mono_arch_create_vars (MonoCompile *cfg)
1483 MonoMethodSignature *sig;
1485 sig = mono_method_signature (cfg->method);
1487 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1488 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1489 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1490 printf ("vret_addr = ");
1491 mono_print_ins (cfg->vret_addr);
1496 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1497 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1501 * take the arguments and generate the arch-specific
1502 * instructions to properly call the function in call.
1503 * This includes pushing, moving arguments to the right register
1505 * Issue: who does the spilling if needed, and when?
1508 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1510 int sig_reg = mono_alloc_ireg (cfg);
1512 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1513 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1514 mips_sp, cinfo->sig_cookie.offset, sig_reg);
1518 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1521 MonoMethodSignature *sig;
1526 sig = call->signature;
1527 n = sig->param_count + sig->hasthis;
1529 cinfo = calculate_sizes (sig, sig->pinvoke);
1530 if (cinfo->struct_ret)
1531 call->used_iregs |= 1 << cinfo->struct_ret;
1533 for (i = 0; i < n; ++i) {
1534 ArgInfo *ainfo = cinfo->args + i;
1537 if (i >= sig->hasthis)
1538 t = sig->params [i - sig->hasthis];
1540 t = &mono_defaults.int_class->byval_arg;
1541 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1543 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1544 emit_sig_cookie (cfg, call, cinfo);
1545 if (is_virtual && i == 0) {
1546 /* the argument will be attached to the call instrucion */
1547 in = call->args [i];
1548 call->used_iregs |= 1 << ainfo->reg;
1551 in = call->args [i];
1552 if (ainfo->regtype == RegTypeGeneral) {
1553 #if SIZEOF_REGISTER == 4
1554 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1555 MONO_INST_NEW (cfg, ins, OP_MOVE);
1556 ins->dreg = mono_alloc_ireg (cfg);
1557 ins->sreg1 = in->dreg + 1;
1558 MONO_ADD_INS (cfg->cbb, ins);
1559 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1561 MONO_INST_NEW (cfg, ins, OP_MOVE);
1562 ins->dreg = mono_alloc_ireg (cfg);
1563 ins->sreg1 = in->dreg + 2;
1564 MONO_ADD_INS (cfg->cbb, ins);
1565 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1568 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1571 #if PROMOTE_R4_TO_R8
1572 /* ??? - convert to single first? */
1573 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1574 ins->dreg = mono_alloc_freg (cfg);
1575 ins->sreg1 = in->dreg;
1576 MONO_ADD_INS (cfg->cbb, ins);
1581 /* trying to load float value into int registers */
1582 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1583 ins->dreg = mono_alloc_ireg (cfg);
1585 MONO_ADD_INS (cfg->cbb, ins);
1586 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1587 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1588 /* trying to load float value into int registers */
1589 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1590 ins->dreg = mono_alloc_ireg (cfg);
1591 ins->sreg1 = in->dreg;
1592 MONO_ADD_INS (cfg->cbb, ins);
1593 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1595 MONO_INST_NEW (cfg, ins, OP_MOVE);
1596 ins->dreg = mono_alloc_ireg (cfg);
1597 ins->sreg1 = in->dreg;
1598 MONO_ADD_INS (cfg->cbb, ins);
1599 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1601 } else if (ainfo->regtype == RegTypeStructByAddr) {
1602 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1603 ins->opcode = OP_OUTARG_VT;
1604 ins->sreg1 = in->dreg;
1605 ins->klass = in->klass;
1606 ins->inst_p0 = call;
1607 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1608 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1609 MONO_ADD_INS (cfg->cbb, ins);
1610 } else if (ainfo->regtype == RegTypeStructByVal) {
1611 /* this is further handled in mono_arch_emit_outarg_vt () */
1612 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1613 ins->opcode = OP_OUTARG_VT;
1614 ins->sreg1 = in->dreg;
1615 ins->klass = in->klass;
1616 ins->inst_p0 = call;
1617 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1618 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1619 MONO_ADD_INS (cfg->cbb, ins);
1620 } else if (ainfo->regtype == RegTypeBase) {
1621 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1622 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1623 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1624 if (t->type == MONO_TYPE_R8)
1625 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1627 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1629 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1631 } else if (ainfo->regtype == RegTypeFP) {
1632 if (t->type == MONO_TYPE_VALUETYPE) {
1633 /* this is further handled in mono_arch_emit_outarg_vt () */
1634 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1635 ins->opcode = OP_OUTARG_VT;
1636 ins->sreg1 = in->dreg;
1637 ins->klass = in->klass;
1638 ins->inst_p0 = call;
1639 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1640 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1641 MONO_ADD_INS (cfg->cbb, ins);
1643 cfg->flags |= MONO_CFG_HAS_FPOUT;
1645 int dreg = mono_alloc_freg (cfg);
1647 if (ainfo->size == 4) {
1648 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1650 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1652 ins->sreg1 = in->dreg;
1653 MONO_ADD_INS (cfg->cbb, ins);
1656 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1657 cfg->flags |= MONO_CFG_HAS_FPOUT;
1660 g_assert_not_reached ();
1664 /* Emit the signature cookie in the case that there is no
1665 additional argument */
1666 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1667 emit_sig_cookie (cfg, call, cinfo);
1669 if (cinfo->struct_ret) {
1672 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1673 vtarg->sreg1 = call->vret_var->dreg;
1674 vtarg->dreg = mono_alloc_preg (cfg);
1675 MONO_ADD_INS (cfg->cbb, vtarg);
1677 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1681 * Reverse the call->out_args list.
1684 MonoInst *prev = NULL, *list = call->out_args, *next;
1691 call->out_args = prev;
1694 call->stack_usage = cinfo->stack_usage;
1695 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1696 #if _MIPS_SIM == _ABIO32
1697 /* a0-a3 always present */
1698 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1700 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1701 cfg->flags |= MONO_CFG_HAS_CALLS;
1703 * should set more info in call, such as the stack space
1704 * used by the args that needs to be added back to esp
1711 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1713 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1714 ArgInfo *ainfo = ins->inst_p1;
1715 int ovf_size = ainfo->vtsize;
1716 int doffset = ainfo->offset;
1717 int i, soffset, dreg;
1719 if (ainfo->regtype == RegTypeStructByVal) {
1721 if (cfg->verbose_level > 0) {
1722 char* nm = mono_method_full_name (cfg->method, TRUE);
1723 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1724 nm, doffset, ainfo->size, ovf_size);
1730 for (i = 0; i < ainfo->size; ++i) {
1731 dreg = mono_alloc_ireg (cfg);
1732 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1733 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1734 soffset += SIZEOF_REGISTER;
1736 if (ovf_size != 0) {
1737 mini_emit_memcpy (cfg, mips_fp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1739 } else if (ainfo->regtype == RegTypeFP) {
1740 int tmpr = mono_alloc_freg (cfg);
1742 if (ainfo->size == 4)
1743 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1745 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1746 dreg = mono_alloc_freg (cfg);
1747 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1748 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1750 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1754 /* FIXME: alignment? */
1755 if (call->signature->pinvoke) {
1756 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1757 vtcopy->backend.is_pinvoke = 1;
1759 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1762 g_assert (ovf_size > 0);
1764 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1765 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1768 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1770 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1775 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1777 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1778 mono_method_signature (method)->ret);
1781 #if (SIZEOF_REGISTER == 4)
1782 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1785 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1786 ins->sreg1 = val->dreg + 1;
1787 ins->sreg2 = val->dreg + 2;
1788 MONO_ADD_INS (cfg->cbb, ins);
1792 if (ret->type == MONO_TYPE_R8) {
1793 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1796 if (ret->type == MONO_TYPE_R4) {
1797 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1801 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1805 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1807 MonoInst *ins, *n, *last_ins = NULL;
1809 if (cfg->verbose_level > 2)
1810 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1813 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1814 if (cfg->verbose_level > 2)
1815 mono_print_ins_index (0, ins);
1817 switch (ins->opcode) {
1819 case OP_LOAD_MEMBASE:
1820 case OP_LOADI4_MEMBASE:
1822 * OP_IADD reg2, reg1, const1
1823 * OP_LOAD_MEMBASE const2(reg2), reg3
1825 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1827 if (last_ins && (last_ins->opcode == OP_IADD_IMM || last_ins->opcode == OP_ADD_IMM) && (last_ins->dreg == ins->inst_basereg) && (last_ins->sreg1 != last_ins->dreg)){
1828 int const1 = last_ins->inst_imm;
1829 int const2 = ins->inst_offset;
1831 if (mips_is_imm16 (const1 + const2)) {
1832 ins->inst_basereg = last_ins->sreg1;
1833 ins->inst_offset = const1 + const2;
1843 bb->last_ins = last_ins;
1847 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1849 MonoInst *ins, *n, *last_ins = NULL;
1852 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1853 MonoInst *last_ins = ins->prev;
1855 switch (ins->opcode) {
1857 /* remove unnecessary multiplication with 1 */
1858 if (ins->inst_imm == 1) {
1859 if (ins->dreg != ins->sreg1) {
1860 ins->opcode = OP_MOVE;
1862 MONO_DELETE_INS (bb, ins);
1866 int power2 = mono_is_power_of_two (ins->inst_imm);
1868 ins->opcode = OP_SHL_IMM;
1869 ins->inst_imm = power2;
1873 case OP_LOAD_MEMBASE:
1874 case OP_LOADI4_MEMBASE:
1876 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1877 * OP_LOAD_MEMBASE offset(basereg), reg
1879 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1880 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1881 ins->inst_basereg == last_ins->inst_destbasereg &&
1882 ins->inst_offset == last_ins->inst_offset) {
1883 if (ins->dreg == last_ins->sreg1) {
1884 MONO_DELETE_INS (bb, ins);
1887 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1888 ins->opcode = OP_MOVE;
1889 ins->sreg1 = last_ins->sreg1;
1894 * Note: reg1 must be different from the basereg in the second load
1895 * OP_LOAD_MEMBASE offset(basereg), reg1
1896 * OP_LOAD_MEMBASE offset(basereg), reg2
1898 * OP_LOAD_MEMBASE offset(basereg), reg1
1899 * OP_MOVE reg1, reg2
1901 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1902 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1903 ins->inst_basereg != last_ins->dreg &&
1904 ins->inst_basereg == last_ins->inst_basereg &&
1905 ins->inst_offset == last_ins->inst_offset) {
1907 if (ins->dreg == last_ins->dreg) {
1908 MONO_DELETE_INS (bb, ins);
1911 ins->opcode = OP_MOVE;
1912 ins->sreg1 = last_ins->dreg;
1915 //g_assert_not_reached ();
1920 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1921 * OP_LOAD_MEMBASE offset(basereg), reg
1923 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1924 * OP_ICONST reg, imm
1926 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1927 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1928 ins->inst_basereg == last_ins->inst_destbasereg &&
1929 ins->inst_offset == last_ins->inst_offset) {
1930 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1931 ins->opcode = OP_ICONST;
1932 ins->inst_c0 = last_ins->inst_imm;
1933 g_assert_not_reached (); // check this rule
1938 case OP_LOADU1_MEMBASE:
1939 case OP_LOADI1_MEMBASE:
1940 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1941 ins->inst_basereg == last_ins->inst_destbasereg &&
1942 ins->inst_offset == last_ins->inst_offset) {
1943 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1944 ins->sreg1 = last_ins->sreg1;
1947 case OP_LOADU2_MEMBASE:
1948 case OP_LOADI2_MEMBASE:
1949 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1950 ins->inst_basereg == last_ins->inst_destbasereg &&
1951 ins->inst_offset == last_ins->inst_offset) {
1952 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1953 ins->sreg1 = last_ins->sreg1;
1956 case OP_ICONV_TO_I4:
1957 case OP_ICONV_TO_U4:
1959 ins->opcode = OP_MOVE;
1963 if (ins->dreg == ins->sreg1) {
1964 MONO_DELETE_INS (bb, ins);
1968 * OP_MOVE sreg, dreg
1969 * OP_MOVE dreg, sreg
1971 if (last_ins && last_ins->opcode == OP_MOVE &&
1972 ins->sreg1 == last_ins->dreg &&
1973 ins->dreg == last_ins->sreg1) {
1974 MONO_DELETE_INS (bb, ins);
1982 bb->last_ins = last_ins;
1986 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
1994 switch (ins->opcode) {
1997 case OP_LCOMPARE_IMM:
1998 mono_print_ins (ins);
1999 g_assert_not_reached ();
2002 tmp1 = mono_alloc_ireg (cfg);
2003 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2004 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2005 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2006 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2011 tmp1 = mono_alloc_ireg (cfg);
2012 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2013 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2014 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2015 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2020 tmp1 = mono_alloc_ireg (cfg);
2021 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2022 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2023 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2024 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2029 tmp1 = mono_alloc_ireg (cfg);
2030 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2031 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2032 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2033 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2045 mono_print_ins (ins);
2046 g_assert_not_reached ();
2049 tmp1 = mono_alloc_ireg (cfg);
2050 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2051 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2052 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2053 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2061 case OP_LCONV_TO_I1:
2062 case OP_LCONV_TO_I2:
2063 case OP_LCONV_TO_I4:
2064 case OP_LCONV_TO_I8:
2065 case OP_LCONV_TO_R4:
2066 case OP_LCONV_TO_R8:
2067 case OP_LCONV_TO_U4:
2068 case OP_LCONV_TO_U8:
2069 case OP_LCONV_TO_U2:
2070 case OP_LCONV_TO_U1:
2072 case OP_LCONV_TO_OVF_I:
2073 case OP_LCONV_TO_OVF_U:
2075 mono_print_ins (ins);
2076 g_assert_not_reached ();
2079 tmp1 = mono_alloc_ireg (cfg);
2080 tmp2 = mono_alloc_ireg (cfg);
2081 tmp3 = mono_alloc_ireg (cfg);
2082 tmp4 = mono_alloc_ireg (cfg);
2083 tmp5 = mono_alloc_ireg (cfg);
2085 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2087 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2088 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2090 /* add the high 32-bits, and add in the carry from the low 32-bits */
2091 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2092 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2094 /* Overflow happens if
2095 * neg + neg = pos or
2097 * XOR of the high bits returns 0 if the signs match
2098 * XOR of that with the high bit of the result return 1 if overflow.
2101 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2102 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2104 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2105 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2106 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2108 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2109 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2110 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2112 /* Now, if (tmp4 == 0) then overflow */
2113 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2117 case OP_LADD_OVF_UN:
2118 tmp1 = mono_alloc_ireg (cfg);
2119 tmp2 = mono_alloc_ireg (cfg);
2121 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2122 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2123 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2124 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2125 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2126 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2131 case OP_LMUL_OVF_UN:
2132 mono_print_ins (ins);
2133 g_assert_not_reached ();
2136 tmp1 = mono_alloc_ireg (cfg);
2137 tmp2 = mono_alloc_ireg (cfg);
2138 tmp3 = mono_alloc_ireg (cfg);
2139 tmp4 = mono_alloc_ireg (cfg);
2140 tmp5 = mono_alloc_ireg (cfg);
2142 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2144 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2145 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2146 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2148 /* Overflow happens if
2149 * neg - pos = pos or
2151 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2153 * tmp1 = (lhs ^ rhs)
2154 * tmp2 = (lhs ^ result)
2155 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2158 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2159 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2160 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2161 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2163 /* Now, if (tmp4 == 1) then overflow */
2164 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2168 case OP_LSUB_OVF_UN:
2169 tmp1 = mono_alloc_ireg (cfg);
2170 tmp2 = mono_alloc_ireg (cfg);
2172 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2173 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2174 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2175 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2177 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2178 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2182 case OP_LCONV_TO_OVF_I1_UN:
2183 case OP_LCONV_TO_OVF_I2_UN:
2184 case OP_LCONV_TO_OVF_I4_UN:
2185 case OP_LCONV_TO_OVF_I8_UN:
2186 case OP_LCONV_TO_OVF_U1_UN:
2187 case OP_LCONV_TO_OVF_U2_UN:
2188 case OP_LCONV_TO_OVF_U4_UN:
2189 case OP_LCONV_TO_OVF_U8_UN:
2190 case OP_LCONV_TO_OVF_I_UN:
2191 case OP_LCONV_TO_OVF_U_UN:
2192 case OP_LCONV_TO_OVF_I1:
2193 case OP_LCONV_TO_OVF_U1:
2194 case OP_LCONV_TO_OVF_I2:
2195 case OP_LCONV_TO_OVF_U2:
2196 case OP_LCONV_TO_OVF_I4:
2197 case OP_LCONV_TO_OVF_U4:
2198 case OP_LCONV_TO_OVF_I8:
2199 case OP_LCONV_TO_OVF_U8:
2207 case OP_LCONV_TO_R_UN:
2213 case OP_LSHR_UN_IMM:
2215 case OP_LDIV_UN_IMM:
2217 case OP_LREM_UN_IMM:
2228 mono_print_ins (ins);
2229 g_assert_not_reached ();
2231 case OP_LCONV_TO_R8_2:
2232 case OP_LCONV_TO_R4_2:
2233 case OP_LCONV_TO_R_UN_2:
2235 case OP_LCONV_TO_OVF_I4_2:
2236 tmp1 = mono_alloc_ireg (cfg);
2238 /* Overflows if reg2 != sign extension of reg1 */
2239 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2240 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2241 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2249 mono_print_ins (ins);
2250 g_assert_not_reached ();
2258 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2266 switch (ins->opcode) {
2268 tmp1 = mono_alloc_ireg (cfg);
2269 tmp2 = mono_alloc_ireg (cfg);
2270 tmp3 = mono_alloc_ireg (cfg);
2271 tmp4 = mono_alloc_ireg (cfg);
2272 tmp5 = mono_alloc_ireg (cfg);
2274 /* add the operands */
2276 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2278 /* Overflow happens if
2279 * neg + neg = pos or
2282 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2283 * XOR of the high bit returns 0 if the signs match
2284 * XOR of that with the high bit of the result return 1 if overflow.
2287 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2288 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2290 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2291 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2292 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2294 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2295 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2297 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2299 /* Now, if (tmp5 == 0) then overflow */
2300 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2301 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2302 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2306 case OP_IADD_OVF_UN:
2307 tmp1 = mono_alloc_ireg (cfg);
2309 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2310 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2311 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2312 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2313 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2318 tmp1 = mono_alloc_ireg (cfg);
2319 tmp2 = mono_alloc_ireg (cfg);
2320 tmp3 = mono_alloc_ireg (cfg);
2321 tmp4 = mono_alloc_ireg (cfg);
2322 tmp5 = mono_alloc_ireg (cfg);
2324 /* add the operands */
2326 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2328 /* Overflow happens if
2329 * neg - pos = pos or
2331 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2333 * tmp1 = (lhs ^ rhs)
2334 * tmp2 = (lhs ^ result)
2335 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2338 /* tmp3 = 1 if the signs of the two inputs differ */
2339 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2340 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2341 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2342 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2343 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2345 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2346 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2347 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2351 case OP_ISUB_OVF_UN:
2352 tmp1 = mono_alloc_ireg (cfg);
2354 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2355 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2356 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2357 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2358 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2365 map_to_reg_reg_op (int op)
2374 case OP_COMPARE_IMM:
2376 case OP_ICOMPARE_IMM:
2378 case OP_LCOMPARE_IMM:
2394 case OP_LOAD_MEMBASE:
2395 return OP_LOAD_MEMINDEX;
2396 case OP_LOADI4_MEMBASE:
2397 return OP_LOADI4_MEMINDEX;
2398 case OP_LOADU4_MEMBASE:
2399 return OP_LOADU4_MEMINDEX;
2400 case OP_LOADU1_MEMBASE:
2401 return OP_LOADU1_MEMINDEX;
2402 case OP_LOADI2_MEMBASE:
2403 return OP_LOADI2_MEMINDEX;
2404 case OP_LOADU2_MEMBASE:
2405 return OP_LOADU2_MEMINDEX;
2406 case OP_LOADI1_MEMBASE:
2407 return OP_LOADI1_MEMINDEX;
2408 case OP_LOADR4_MEMBASE:
2409 return OP_LOADR4_MEMINDEX;
2410 case OP_LOADR8_MEMBASE:
2411 return OP_LOADR8_MEMINDEX;
2412 case OP_STOREI1_MEMBASE_REG:
2413 return OP_STOREI1_MEMINDEX;
2414 case OP_STOREI2_MEMBASE_REG:
2415 return OP_STOREI2_MEMINDEX;
2416 case OP_STOREI4_MEMBASE_REG:
2417 return OP_STOREI4_MEMINDEX;
2418 case OP_STORE_MEMBASE_REG:
2419 return OP_STORE_MEMINDEX;
2420 case OP_STORER4_MEMBASE_REG:
2421 return OP_STORER4_MEMINDEX;
2422 case OP_STORER8_MEMBASE_REG:
2423 return OP_STORER8_MEMINDEX;
2424 case OP_STORE_MEMBASE_IMM:
2425 return OP_STORE_MEMBASE_REG;
2426 case OP_STOREI1_MEMBASE_IMM:
2427 return OP_STOREI1_MEMBASE_REG;
2428 case OP_STOREI2_MEMBASE_IMM:
2429 return OP_STOREI2_MEMBASE_REG;
2430 case OP_STOREI4_MEMBASE_IMM:
2431 return OP_STOREI4_MEMBASE_REG;
2432 case OP_STOREI8_MEMBASE_IMM:
2433 return OP_STOREI8_MEMBASE_REG;
2435 return mono_op_imm_to_op (op);
2439 map_to_mips_op (int op)
2443 return OP_MIPS_FBEQ;
2445 return OP_MIPS_FBGE;
2447 return OP_MIPS_FBGT;
2449 return OP_MIPS_FBLE;
2451 return OP_MIPS_FBLT;
2453 return OP_MIPS_FBNE;
2455 return OP_MIPS_FBGE_UN;
2457 return OP_MIPS_FBGT_UN;
2459 return OP_MIPS_FBLE_UN;
2461 return OP_MIPS_FBLT_UN;
2469 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2470 g_assert_not_reached ();
2474 #define NEW_INS(cfg,after,dest,op) do { \
2475 MONO_INST_NEW((cfg), (dest), (op)); \
2476 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2479 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2481 MONO_INST_NEW(cfg, temp, (op)); \
2482 mono_bblock_insert_after_ins (bb, (pos), temp); \
2483 temp->dreg = (_dreg); \
2484 temp->sreg1 = (_sreg1); \
2485 temp->sreg2 = (_sreg2); \
2489 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2491 MONO_INST_NEW(cfg, temp, (op)); \
2492 mono_bblock_insert_after_ins (bb, (pos), temp); \
2493 temp->dreg = (_dreg); \
2494 temp->sreg1 = (_sreg1); \
2495 temp->inst_c0 = (_imm); \
2500 * Remove from the instruction list the instructions that can't be
2501 * represented with very simple instructions with no register
2505 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2507 MonoInst *ins, *next, *temp, *last_ins = NULL;
2511 if (cfg->verbose_level > 2) {
2514 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2515 MONO_BB_FOR_EACH_INS (bb, ins) {
2516 mono_print_ins_index (idx++, ins);
2522 MONO_BB_FOR_EACH_INS (bb, ins) {
2524 switch (ins->opcode) {
2529 /* Branch opts can eliminate the branch */
2530 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2536 case OP_COMPARE_IMM:
2537 case OP_ICOMPARE_IMM:
2538 case OP_LCOMPARE_IMM:
2540 /* Branch opts can eliminate the branch */
2541 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2545 if (ins->inst_imm) {
2546 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2547 temp->inst_c0 = ins->inst_imm;
2548 temp->dreg = mono_alloc_ireg (cfg);
2549 ins->sreg2 = temp->dreg;
2553 ins->sreg2 = mips_zero;
2555 if (ins->opcode == OP_COMPARE_IMM)
2556 ins->opcode = OP_COMPARE;
2557 else if (ins->opcode == OP_ICOMPARE_IMM)
2558 ins->opcode = OP_ICOMPARE;
2559 else if (ins->opcode == OP_LCOMPARE_IMM)
2560 ins->opcode = OP_LCOMPARE;
2563 case OP_IDIV_UN_IMM:
2566 case OP_IREM_UN_IMM:
2567 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2568 temp->inst_c0 = ins->inst_imm;
2569 temp->dreg = mono_alloc_ireg (cfg);
2570 ins->sreg2 = temp->dreg;
2571 if (ins->opcode == OP_IDIV_IMM)
2572 ins->opcode = OP_IDIV;
2573 else if (ins->opcode == OP_IREM_IMM)
2574 ins->opcode = OP_IREM;
2575 else if (ins->opcode == OP_IDIV_UN_IMM)
2576 ins->opcode = OP_IDIV_UN;
2577 else if (ins->opcode == OP_IREM_UN_IMM)
2578 ins->opcode = OP_IREM_UN;
2580 /* handle rem separately */
2587 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2588 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2589 temp->inst_c0 = ins->inst_imm;
2590 temp->dreg = mono_alloc_ireg (cfg);
2591 ins->sreg2 = temp->dreg;
2592 ins->opcode = map_to_reg_reg_op (ins->opcode);
2602 /* unsigned 16 bit immediate */
2603 if (ins->inst_imm & 0xffff0000) {
2604 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2605 temp->inst_c0 = ins->inst_imm;
2606 temp->dreg = mono_alloc_ireg (cfg);
2607 ins->sreg2 = temp->dreg;
2608 ins->opcode = map_to_reg_reg_op (ins->opcode);
2615 /* signed 16 bit immediate */
2616 if (!mips_is_imm16 (ins->inst_imm)) {
2617 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2618 temp->inst_c0 = ins->inst_imm;
2619 temp->dreg = mono_alloc_ireg (cfg);
2620 ins->sreg2 = temp->dreg;
2621 ins->opcode = map_to_reg_reg_op (ins->opcode);
2627 if (!mips_is_imm16 (-ins->inst_imm)) {
2628 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2629 temp->inst_c0 = ins->inst_imm;
2630 temp->dreg = mono_alloc_ireg (cfg);
2631 ins->sreg2 = temp->dreg;
2632 ins->opcode = map_to_reg_reg_op (ins->opcode);
2638 if (ins->inst_imm == 1) {
2639 ins->opcode = OP_MOVE;
2642 if (ins->inst_imm == 0) {
2643 ins->opcode = OP_ICONST;
2647 imm = mono_is_power_of_two (ins->inst_imm);
2649 ins->opcode = OP_SHL_IMM;
2650 ins->inst_imm = imm;
2653 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2654 temp->inst_c0 = ins->inst_imm;
2655 temp->dreg = mono_alloc_ireg (cfg);
2656 ins->sreg2 = temp->dreg;
2657 ins->opcode = map_to_reg_reg_op (ins->opcode);
2660 case OP_LOCALLOC_IMM:
2661 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2662 temp->inst_c0 = ins->inst_imm;
2663 temp->dreg = mono_alloc_ireg (cfg);
2664 ins->sreg1 = temp->dreg;
2665 ins->opcode = OP_LOCALLOC;
2668 case OP_LOADR4_MEMBASE:
2669 case OP_STORER4_MEMBASE_REG:
2670 /* we can do two things: load the immed in a register
2671 * and use an indexed load, or see if the immed can be
2672 * represented as an ad_imm + a load with a smaller offset
2673 * that fits. We just do the first for now, optimize later.
2675 if (mips_is_imm16 (ins->inst_offset))
2677 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2678 temp->inst_c0 = ins->inst_offset;
2679 temp->dreg = mono_alloc_ireg (cfg);
2680 ins->sreg2 = temp->dreg;
2681 ins->opcode = map_to_reg_reg_op (ins->opcode);
2684 case OP_STORE_MEMBASE_IMM:
2685 case OP_STOREI1_MEMBASE_IMM:
2686 case OP_STOREI2_MEMBASE_IMM:
2687 case OP_STOREI4_MEMBASE_IMM:
2688 case OP_STOREI8_MEMBASE_IMM:
2689 if (!ins->inst_imm) {
2690 ins->sreg1 = mips_zero;
2691 ins->opcode = map_to_reg_reg_op (ins->opcode);
2694 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2695 temp->inst_c0 = ins->inst_imm;
2696 temp->dreg = mono_alloc_ireg (cfg);
2697 ins->sreg1 = temp->dreg;
2698 ins->opcode = map_to_reg_reg_op (ins->opcode);
2700 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2706 /* Branch opts can eliminate the branch */
2707 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2714 * remap compare/branch and compare/set
2715 * to MIPS specific opcodes.
2717 next->opcode = map_to_mips_op (next->opcode);
2718 next->sreg1 = ins->sreg1;
2719 next->sreg2 = ins->sreg2;
2726 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2727 temp->inst_c0 = (guint32)ins->inst_p0;
2728 temp->dreg = mono_alloc_ireg (cfg);
2729 ins->inst_basereg = temp->dreg;
2730 ins->inst_offset = 0;
2731 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2733 /* make it handle the possibly big ins->inst_offset
2734 * later optimize to use lis + load_membase
2739 g_assert (ins_is_compare(last_ins));
2740 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2741 NULLIFY_INS(last_ins);
2745 g_assert (ins_is_compare(last_ins));
2746 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2747 NULLIFY_INS(last_ins);
2751 g_assert (ins_is_compare(last_ins));
2752 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2753 last_ins->dreg = mono_alloc_ireg (cfg);
2754 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2758 g_assert (ins_is_compare(last_ins));
2759 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2760 last_ins->dreg = mono_alloc_ireg (cfg);
2761 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2765 g_assert (ins_is_compare(last_ins));
2766 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2767 last_ins->dreg = mono_alloc_ireg (cfg);
2768 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2772 g_assert (ins_is_compare(last_ins));
2773 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2774 last_ins->dreg = mono_alloc_ireg (cfg);
2775 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2779 g_assert (ins_is_compare(last_ins));
2780 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2781 last_ins->dreg = mono_alloc_ireg (cfg);
2782 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2786 g_assert (ins_is_compare(last_ins));
2787 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2788 last_ins->dreg = mono_alloc_ireg (cfg);
2789 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2793 g_assert (ins_is_compare(last_ins));
2794 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2795 last_ins->dreg = mono_alloc_ireg (cfg);
2796 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2800 g_assert (ins_is_compare(last_ins));
2801 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2802 last_ins->dreg = mono_alloc_ireg (cfg);
2803 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2808 g_assert (ins_is_compare(last_ins));
2809 last_ins->opcode = OP_IXOR;
2810 last_ins->dreg = mono_alloc_ireg(cfg);
2811 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2816 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2817 NULLIFY_INS(last_ins);
2823 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2824 NULLIFY_INS(last_ins);
2829 g_assert (ins_is_compare(last_ins));
2830 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2831 MONO_DELETE_INS(bb, last_ins);
2836 g_assert (ins_is_compare(last_ins));
2837 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2838 MONO_DELETE_INS(bb, last_ins);
2841 case OP_COND_EXC_EQ:
2842 case OP_COND_EXC_IEQ:
2843 g_assert (ins_is_compare(last_ins));
2844 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2845 MONO_DELETE_INS(bb, last_ins);
2848 case OP_COND_EXC_GE:
2849 case OP_COND_EXC_IGE:
2850 g_assert (ins_is_compare(last_ins));
2851 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2852 MONO_DELETE_INS(bb, last_ins);
2855 case OP_COND_EXC_GT:
2856 case OP_COND_EXC_IGT:
2857 g_assert (ins_is_compare(last_ins));
2858 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2859 MONO_DELETE_INS(bb, last_ins);
2862 case OP_COND_EXC_LE:
2863 case OP_COND_EXC_ILE:
2864 g_assert (ins_is_compare(last_ins));
2865 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2866 MONO_DELETE_INS(bb, last_ins);
2869 case OP_COND_EXC_LT:
2870 case OP_COND_EXC_ILT:
2871 g_assert (ins_is_compare(last_ins));
2872 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2873 MONO_DELETE_INS(bb, last_ins);
2876 case OP_COND_EXC_NE_UN:
2877 case OP_COND_EXC_INE_UN:
2878 g_assert (ins_is_compare(last_ins));
2879 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2880 MONO_DELETE_INS(bb, last_ins);
2883 case OP_COND_EXC_GE_UN:
2884 case OP_COND_EXC_IGE_UN:
2885 g_assert (ins_is_compare(last_ins));
2886 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2887 MONO_DELETE_INS(bb, last_ins);
2890 case OP_COND_EXC_GT_UN:
2891 case OP_COND_EXC_IGT_UN:
2892 g_assert (ins_is_compare(last_ins));
2893 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2894 MONO_DELETE_INS(bb, last_ins);
2897 case OP_COND_EXC_LE_UN:
2898 case OP_COND_EXC_ILE_UN:
2899 g_assert (ins_is_compare(last_ins));
2900 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2901 MONO_DELETE_INS(bb, last_ins);
2904 case OP_COND_EXC_LT_UN:
2905 case OP_COND_EXC_ILT_UN:
2906 g_assert (ins_is_compare(last_ins));
2907 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2908 MONO_DELETE_INS(bb, last_ins);
2911 case OP_COND_EXC_OV:
2912 case OP_COND_EXC_IOV: {
2913 int tmp1, tmp2, tmp3, tmp4, tmp5;
2914 MonoInst *pos = last_ins;
2916 /* Overflow happens if
2917 * neg + neg = pos or
2920 * (bit31s of operands match) AND (bit31 of operand
2921 * != bit31 of result)
2922 * XOR of the high bit returns 0 if the signs match
2923 * XOR of that with the high bit of the result return 1
2926 g_assert (last_ins->opcode == OP_IADC);
2928 tmp1 = mono_alloc_ireg (cfg);
2929 tmp2 = mono_alloc_ireg (cfg);
2930 tmp3 = mono_alloc_ireg (cfg);
2931 tmp4 = mono_alloc_ireg (cfg);
2932 tmp5 = mono_alloc_ireg (cfg);
2934 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2935 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2937 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2938 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2939 INS (pos, OP_INOT, tmp3, tmp2, -1);
2941 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2942 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2943 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2945 /* Now, if (tmp5 == 0) then overflow */
2946 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2951 case OP_COND_EXC_NO:
2952 case OP_COND_EXC_INO:
2953 g_assert_not_reached ();
2957 case OP_COND_EXC_IC:
2958 g_assert_not_reached ();
2961 case OP_COND_EXC_NC:
2962 case OP_COND_EXC_INC:
2963 g_assert_not_reached ();
2969 bb->last_ins = last_ins;
2970 bb->max_vreg = cfg->next_vreg;
2973 if (cfg->verbose_level > 2) {
2976 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
2977 MONO_BB_FOR_EACH_INS (bb, ins) {
2978 mono_print_ins_index (idx++, ins);
2987 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2989 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
2991 mips_truncwd (code, mips_ftemp, sreg);
2993 mips_cvtwd (code, mips_ftemp, sreg);
2995 mips_mfc1 (code, dreg, mips_ftemp);
2998 mips_andi (code, dreg, dreg, 0xff);
2999 else if (size == 2) {
3000 mips_sll (code, dreg, dreg, 16);
3001 mips_srl (code, dreg, dreg, 16);
3005 mips_sll (code, dreg, dreg, 24);
3006 mips_sra (code, dreg, dreg, 24);
3008 else if (size == 2) {
3009 mips_sll (code, dreg, dreg, 16);
3010 mips_sra (code, dreg, dreg, 16);
3017 * emit_load_volatile_arguments:
3019 * Load volatile arguments from the stack to the original input registers.
3020 * Required before a tail call.
3023 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3025 MonoMethod *method = cfg->method;
3026 MonoMethodSignature *sig;
3031 sig = mono_method_signature (method);
3032 cinfo = calculate_sizes (sig, sig->pinvoke);
3033 if (cinfo->struct_ret) {
3034 ArgInfo *ainfo = &cinfo->ret;
3035 inst = cfg->vret_addr;
3036 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3039 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3040 ArgInfo *ainfo = cinfo->args + i;
3041 inst = cfg->args [i];
3042 if (inst->opcode == OP_REGVAR) {
3043 if (ainfo->regtype == RegTypeGeneral)
3044 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3045 else if (ainfo->regtype == RegTypeFP)
3046 g_assert_not_reached();
3047 else if (ainfo->regtype == RegTypeBase) {
3050 g_assert_not_reached ();
3052 if (ainfo->regtype == RegTypeGeneral) {
3053 g_assert (mips_is_imm16 (inst->inst_offset));
3054 switch (ainfo->size) {
3056 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3059 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3063 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3066 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3067 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3070 g_assert_not_reached ();
3073 } else if (ainfo->regtype == RegTypeBase) {
3075 } else if (ainfo->regtype == RegTypeFP) {
3076 g_assert (mips_is_imm16 (inst->inst_offset));
3077 if (ainfo->size == 8) {
3078 #if _MIPS_SIM == _ABIO32
3079 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3080 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3081 #elif _MIPS_SIM == _ABIN32
3082 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3085 else if (ainfo->size == 4)
3086 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3088 g_assert_not_reached ();
3089 } else if (ainfo->regtype == RegTypeStructByVal) {
3091 int doffset = inst->inst_offset;
3093 g_assert (mips_is_imm16 (inst->inst_offset));
3094 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3095 for (i = 0; i < ainfo->size; ++i) {
3096 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3097 doffset += SIZEOF_REGISTER;
3099 } else if (ainfo->regtype == RegTypeStructByAddr) {
3100 g_assert (mips_is_imm16 (inst->inst_offset));
3101 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3103 g_assert_not_reached ();
3113 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3115 int size = cfg->param_area;
3117 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3118 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3123 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3124 if (ppc_is_imm16 (-size)) {
3125 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3127 ppc_load (code, ppc_r11, -size);
3128 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3135 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3137 int size = cfg->param_area;
3139 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3140 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3145 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3146 if (ppc_is_imm16 (size)) {
3147 ppc_stwu (code, ppc_r0, size, ppc_sp);
3149 ppc_load (code, ppc_r11, size);
3150 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3157 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3162 guint8 *code = cfg->native_code + cfg->code_len;
3163 MonoInst *last_ins = NULL;
3164 guint last_offset = 0;
3168 /* we don't align basic blocks of loops on mips */
3170 if (cfg->verbose_level > 2)
3171 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3173 cpos = bb->max_offset;
3176 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3177 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3178 g_assert (!mono_compile_aot);
3181 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3182 /* this is not thread save, but good enough */
3183 /* fixme: howto handle overflows? */
3184 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3185 mips_lw (code, mips_temp, mips_at, 0);
3186 mips_addiu (code, mips_temp, mips_temp, 1);
3187 mips_sw (code, mips_temp, mips_at, 0);
3190 MONO_BB_FOR_EACH_INS (bb, ins) {
3191 offset = code - cfg->native_code;
3193 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3195 if (offset > (cfg->code_size - max_len - 16)) {
3196 cfg->code_size *= 2;
3197 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3198 code = cfg->native_code + offset;
3200 mono_debug_record_line_number (cfg, ins, offset);
3201 if (cfg->verbose_level > 2) {
3202 g_print (" @ 0x%x\t", offset);
3203 mono_print_ins_index (ins_cnt++, ins);
3205 /* Check for virtual regs that snuck by */
3206 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3208 switch (ins->opcode) {
3209 case OP_RELAXED_NOP:
3212 case OP_DUMMY_STORE:
3213 case OP_NOT_REACHED:
3216 case OP_SEQ_POINT: {
3217 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3218 guint32 addr = (guint32)ss_trigger_page;
3220 mips_load_const (code, mips_t9, addr);
3221 mips_lw (code, mips_t9, mips_t9, 0);
3224 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3227 * A placeholder for a possible breakpoint inserted by
3228 * mono_arch_set_breakpoint ().
3230 /* mips_load_const () + mips_lw */
3237 g_assert_not_reached();
3239 emit_tls_access (code, ins->dreg, ins->inst_offset);
3243 mips_mult (code, ins->sreg1, ins->sreg2);
3244 mips_mflo (code, ins->dreg);
3245 mips_mfhi (code, ins->dreg+1);
3248 mips_multu (code, ins->sreg1, ins->sreg2);
3249 mips_mflo (code, ins->dreg);
3250 mips_mfhi (code, ins->dreg+1);
3252 case OP_MEMORY_BARRIER:
3257 case OP_STOREI1_MEMBASE_IMM:
3258 mips_load_const (code, mips_temp, ins->inst_imm);
3259 if (mips_is_imm16 (ins->inst_offset)) {
3260 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3262 mips_load_const (code, mips_at, ins->inst_offset);
3263 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3266 case OP_STOREI2_MEMBASE_IMM:
3267 mips_load_const (code, mips_temp, ins->inst_imm);
3268 if (mips_is_imm16 (ins->inst_offset)) {
3269 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3271 mips_load_const (code, mips_at, ins->inst_offset);
3272 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3275 case OP_STOREI8_MEMBASE_IMM:
3276 mips_load_const (code, mips_temp, ins->inst_imm);
3277 if (mips_is_imm16 (ins->inst_offset)) {
3278 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3280 mips_load_const (code, mips_at, ins->inst_offset);
3281 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3284 case OP_STORE_MEMBASE_IMM:
3285 case OP_STOREI4_MEMBASE_IMM:
3286 mips_load_const (code, mips_temp, ins->inst_imm);
3287 if (mips_is_imm16 (ins->inst_offset)) {
3288 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3290 mips_load_const (code, mips_at, ins->inst_offset);
3291 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3294 case OP_STOREI1_MEMBASE_REG:
3295 if (mips_is_imm16 (ins->inst_offset)) {
3296 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3298 mips_load_const (code, mips_at, ins->inst_offset);
3299 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3300 mips_sb (code, ins->sreg1, mips_at, 0);
3303 case OP_STOREI2_MEMBASE_REG:
3304 if (mips_is_imm16 (ins->inst_offset)) {
3305 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3307 mips_load_const (code, mips_at, ins->inst_offset);
3308 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3309 mips_sh (code, ins->sreg1, mips_at, 0);
3312 case OP_STORE_MEMBASE_REG:
3313 case OP_STOREI4_MEMBASE_REG:
3314 if (mips_is_imm16 (ins->inst_offset)) {
3315 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3317 mips_load_const (code, mips_at, ins->inst_offset);
3318 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3319 mips_sw (code, ins->sreg1, mips_at, 0);
3322 case OP_STOREI8_MEMBASE_REG:
3323 if (mips_is_imm16 (ins->inst_offset)) {
3324 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3326 mips_load_const (code, mips_at, ins->inst_offset);
3327 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3328 mips_sd (code, ins->sreg1, mips_at, 0);
3332 g_assert_not_reached ();
3333 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3334 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3336 case OP_LOADI8_MEMBASE:
3337 if (mips_is_imm16 (ins->inst_offset)) {
3338 mips_ld (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_ld (code, ins->dreg, mips_at, 0);
3345 case OP_LOAD_MEMBASE:
3346 case OP_LOADI4_MEMBASE:
3347 case OP_LOADU4_MEMBASE:
3348 g_assert (ins->dreg != -1);
3349 if (mips_is_imm16 (ins->inst_offset)) {
3350 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3352 mips_load_const (code, mips_at, ins->inst_offset);
3353 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3354 mips_lw (code, ins->dreg, mips_at, 0);
3357 case OP_LOADI1_MEMBASE:
3358 if (mips_is_imm16 (ins->inst_offset)) {
3359 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3361 mips_load_const (code, mips_at, ins->inst_offset);
3362 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3363 mips_lb (code, ins->dreg, mips_at, 0);
3366 case OP_LOADU1_MEMBASE:
3367 if (mips_is_imm16 (ins->inst_offset)) {
3368 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3370 mips_load_const (code, mips_at, ins->inst_offset);
3371 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3372 mips_lbu (code, ins->dreg, mips_at, 0);
3375 case OP_LOADI2_MEMBASE:
3376 if (mips_is_imm16 (ins->inst_offset)) {
3377 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3379 mips_load_const (code, mips_at, ins->inst_offset);
3380 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3381 mips_lh (code, ins->dreg, mips_at, 0);
3384 case OP_LOADU2_MEMBASE:
3385 if (mips_is_imm16 (ins->inst_offset)) {
3386 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3388 mips_load_const (code, mips_at, ins->inst_offset);
3389 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3390 mips_lhu (code, ins->dreg, mips_at, 0);
3393 case OP_ICONV_TO_I1:
3394 mips_sll (code, mips_at, ins->sreg1, 24);
3395 mips_sra (code, ins->dreg, mips_at, 24);
3397 case OP_ICONV_TO_I2:
3398 mips_sll (code, mips_at, ins->sreg1, 16);
3399 mips_sra (code, ins->dreg, mips_at, 16);
3401 case OP_ICONV_TO_U1:
3402 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3404 case OP_ICONV_TO_U2:
3405 mips_sll (code, mips_at, ins->sreg1, 16);
3406 mips_srl (code, ins->dreg, mips_at, 16);
3409 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3412 g_assert (mips_is_imm16 (ins->inst_imm));
3413 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3416 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3419 g_assert (mips_is_imm16 (ins->inst_imm));
3420 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3424 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3425 * So instead of emitting a trap, we emit a call a C function and place a
3428 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3429 (gpointer)"mono_break");
3430 mips_load (code, mips_t9, 0x1f1f1f1f);
3431 mips_jalr (code, mips_t9, mips_ra);
3435 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3438 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3443 g_assert (mips_is_imm16 (ins->inst_imm));
3444 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3447 g_assert (mips_is_imm16 (ins->inst_imm));
3448 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3452 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3455 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3460 // we add the negated value
3461 g_assert (mips_is_imm16 (-ins->inst_imm));
3462 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3466 // we add the negated value
3467 g_assert (mips_is_imm16 (-ins->inst_imm));
3468 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3473 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3479 g_assert (!(ins->inst_imm & 0xffff0000));
3480 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3485 guint32 *divisor_is_m1;
3486 guint32 *dividend_is_minvalue;
3487 guint32 *divisor_is_zero;
3489 mips_load_const (code, mips_at, -1);
3490 divisor_is_m1 = (guint32 *)(void *)code;
3491 mips_bne (code, ins->sreg2, mips_at, 0);
3492 mips_lui (code, mips_at, mips_zero, 0x8000);
3493 dividend_is_minvalue = (guint32 *)(void *)code;
3494 mips_bne (code, ins->sreg1, mips_at, 0);
3497 /* Divide Int32.MinValue by -1 -- throw exception */
3498 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3500 mips_patch (divisor_is_m1, (guint32)code);
3501 mips_patch (dividend_is_minvalue, (guint32)code);
3503 /* Put divide in branch delay slot (NOT YET) */
3504 divisor_is_zero = (guint32 *)(void *)code;
3505 mips_bne (code, ins->sreg2, mips_zero, 0);
3508 /* Divide by zero -- throw exception */
3509 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3511 mips_patch (divisor_is_zero, (guint32)code);
3512 mips_div (code, ins->sreg1, ins->sreg2);
3513 if (ins->opcode == OP_IDIV)
3514 mips_mflo (code, ins->dreg);
3516 mips_mfhi (code, ins->dreg);
3521 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3523 /* Put divide in branch delay slot (NOT YET) */
3524 mips_bne (code, ins->sreg2, mips_zero, 0);
3527 /* Divide by zero -- throw exception */
3528 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3530 mips_patch (divisor_is_zero, (guint32)code);
3531 mips_divu (code, ins->sreg1, ins->sreg2);
3532 if (ins->opcode == OP_IDIV_UN)
3533 mips_mflo (code, ins->dreg);
3535 mips_mfhi (code, ins->dreg);
3539 g_assert_not_reached ();
3541 ppc_load (code, ppc_r11, ins->inst_imm);
3542 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3543 ppc_mfspr (code, ppc_r0, ppc_xer);
3544 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3545 /* FIXME: use OverflowException for 0x80000000/-1 */
3546 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3548 g_assert_not_reached();
3551 g_assert_not_reached ();
3553 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3557 g_assert (!(ins->inst_imm & 0xffff0000));
3558 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3561 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3565 /* unsigned 16-bit immediate */
3566 g_assert (!(ins->inst_imm & 0xffff0000));
3567 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3570 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3574 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3577 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3580 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3584 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3587 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3590 case OP_ISHR_UN_IMM:
3591 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3593 case OP_LSHR_UN_IMM:
3594 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3597 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3600 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3604 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3607 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3610 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3614 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3616 mips_mult (code, ins->sreg1, ins->sreg2);
3617 mips_mflo (code, ins->dreg);
3622 #if SIZEOF_REGISTER == 8
3624 mips_dmult (code, ins->sreg1, ins->sreg2);
3625 mips_mflo (code, ins->dreg);
3630 mips_mult (code, ins->sreg1, ins->sreg2);
3631 mips_mflo (code, ins->dreg);
3632 mips_mfhi (code, mips_at);
3635 mips_sra (code, mips_temp, ins->dreg, 31);
3636 patch = (guint32 *)(void *)code;
3637 mips_beq (code, mips_temp, mips_at, 0);
3639 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3640 mips_patch (patch, (guint32)code);
3643 case OP_IMUL_OVF_UN: {
3645 mips_mult (code, ins->sreg1, ins->sreg2);
3646 mips_mflo (code, ins->dreg);
3647 mips_mfhi (code, mips_at);
3650 patch = (guint32 *)(void *)code;
3651 mips_beq (code, mips_at, mips_zero, 0);
3653 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3654 mips_patch (patch, (guint32)code);
3658 mips_load_const (code, ins->dreg, ins->inst_c0);
3660 #if SIZEOF_REGISTER == 8
3662 mips_load_const (code, ins->dreg, ins->inst_c0);
3666 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3667 mips_load (code, ins->dreg, 0);
3671 mips_mtc1 (code, ins->dreg, ins->sreg1);
3673 case OP_MIPS_MTC1S_2:
3674 mips_mtc1 (code, ins->dreg, ins->sreg1);
3675 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3678 mips_mfc1 (code, ins->dreg, ins->sreg1);
3681 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3685 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3687 mips_mfc1 (code, ins->dreg+1, ins->sreg1);
3688 mips_mfc1 (code, ins->dreg, ins->sreg1+1);
3692 case OP_ICONV_TO_I4:
3693 case OP_ICONV_TO_U4:
3695 if (ins->dreg != ins->sreg1)
3696 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3698 #if SIZEOF_REGISTER == 8
3700 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3701 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3704 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3705 mips_dsra (code, ins->dreg, ins->dreg, 32);
3709 int lsreg = mips_v0 + ls_word_idx;
3710 int msreg = mips_v0 + ms_word_idx;
3712 /* Get sreg1 into lsreg, sreg2 into msreg */
3714 if (ins->sreg1 == msreg) {
3715 if (ins->sreg1 != mips_at)
3716 MIPS_MOVE (code, mips_at, ins->sreg1);
3717 if (ins->sreg2 != msreg)
3718 MIPS_MOVE (code, msreg, ins->sreg2);
3719 MIPS_MOVE (code, lsreg, mips_at);
3722 if (ins->sreg2 != msreg)
3723 MIPS_MOVE (code, msreg, ins->sreg2);
3724 if (ins->sreg1 != lsreg)
3725 MIPS_MOVE (code, lsreg, ins->sreg1);
3730 if (ins->dreg != ins->sreg1) {
3731 mips_fmovd (code, ins->dreg, ins->sreg1);
3735 /* Convert from double to float and leave it there */
3736 mips_cvtsd (code, ins->dreg, ins->sreg1);
3738 case OP_FCONV_TO_R4:
3740 mips_cvtsd (code, ins->dreg, ins->sreg1);
3742 /* Just a move, no precision change */
3743 if (ins->dreg != ins->sreg1) {
3744 mips_fmovd (code, ins->dreg, ins->sreg1);
3749 code = emit_load_volatile_arguments(cfg, code);
3752 * Pop our stack, then jump to specified method (tail-call)
3753 * Keep in sync with mono_arch_emit_epilog
3755 code = mono_arch_emit_epilog_sub (cfg, code);
3757 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3758 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3759 if (cfg->arch.long_branch) {
3760 mips_lui (code, mips_t9, mips_zero, 0);
3761 mips_addiu (code, mips_t9, mips_t9, 0);
3762 mips_jr (code, mips_t9);
3766 mips_beq (code, mips_zero, mips_zero, 0);
3771 /* ensure ins->sreg1 is not NULL */
3772 mips_lw (code, mips_zero, ins->sreg1, 0);
3775 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3776 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3778 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
3779 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
3781 mips_sw (code, mips_at, ins->sreg1, 0);
3794 case OP_VOIDCALL_REG:
3796 case OP_FCALL_MEMBASE:
3797 case OP_LCALL_MEMBASE:
3798 case OP_VCALL_MEMBASE:
3799 case OP_VCALL2_MEMBASE:
3800 case OP_VOIDCALL_MEMBASE:
3801 case OP_CALL_MEMBASE:
3802 call = (MonoCallInst*)ins;
3803 switch (ins->opcode) {
3810 if (ins->flags & MONO_INST_HAS_METHOD) {
3811 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3812 mips_load (code, mips_t9, call->method);
3815 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3816 mips_load (code, mips_t9, call->fptr);
3818 mips_jalr (code, mips_t9, mips_ra);
3825 case OP_VOIDCALL_REG:
3827 MIPS_MOVE (code, mips_t9, ins->sreg1);
3828 mips_jalr (code, mips_t9, mips_ra);
3831 case OP_FCALL_MEMBASE:
3832 case OP_LCALL_MEMBASE:
3833 case OP_VCALL_MEMBASE:
3834 case OP_VCALL2_MEMBASE:
3835 case OP_VOIDCALL_MEMBASE:
3836 case OP_CALL_MEMBASE:
3837 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3838 mips_jalr (code, mips_t9, mips_ra);
3842 #if PROMOTE_R4_TO_R8
3843 /* returned an FP R4 (single), promote to R8 (double) in place */
3844 if ((ins->opcode == OP_FCALL ||
3845 ins->opcode == OP_FCALL_REG) &&
3846 call->signature->ret->type == MONO_TYPE_R4) {
3847 mips_cvtds (code, mips_f0, mips_f0);
3852 int area_offset = cfg->param_area;
3854 /* Round up ins->sreg1, mips_at ends up holding size */
3855 mips_addiu (code, mips_at, ins->sreg1, 31);
3856 mips_addiu (code, mips_temp, mips_zero, ~31);
3857 mips_and (code, mips_at, mips_at, mips_temp);
3859 mips_subu (code, mips_sp, mips_sp, mips_at);
3860 g_assert (mips_is_imm16 (area_offset));
3861 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3863 if (ins->flags & MONO_INST_INIT) {
3864 mips_move (code, mips_temp, ins->dreg);
3865 mips_sb (code, mips_zero, mips_temp, 0);
3866 mips_addiu (code, mips_at, mips_at, -1);
3867 mips_bne (code, mips_at, mips_zero, -3);
3868 mips_addiu (code, mips_temp, mips_temp, 1);
3873 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3874 mips_move (code, mips_a0, ins->sreg1);
3875 mips_call (code, mips_t9, addr);
3876 mips_break (code, 0xfc);
3880 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3881 mips_move (code, mips_a0, ins->sreg1);
3882 mips_call (code, mips_t9, addr);
3883 mips_break (code, 0xfb);
3886 case OP_START_HANDLER: {
3888 * The START_HANDLER instruction marks the beginning of
3889 * a handler block. It is called using a call
3890 * instruction, so mips_ra contains the return address.
3891 * Since the handler executes in the same stack frame
3892 * as the method itself, we can't use save/restore to
3893 * save the return address. Instead, we save it into
3894 * a dedicated variable.
3896 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3897 g_assert (spvar->inst_basereg != mips_sp);
3898 code = emit_reserve_param_area (cfg, code);
3900 if (mips_is_imm16 (spvar->inst_offset)) {
3901 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3903 mips_load_const (code, mips_at, spvar->inst_offset);
3904 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3905 mips_sw (code, mips_ra, mips_at, 0);
3909 case OP_ENDFILTER: {
3910 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3911 g_assert (spvar->inst_basereg != mips_sp);
3912 code = emit_unreserve_param_area (cfg, code);
3914 if (ins->sreg1 != mips_v0)
3915 MIPS_MOVE (code, mips_v0, ins->sreg1);
3916 if (mips_is_imm16 (spvar->inst_offset)) {
3917 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3919 mips_load_const (code, mips_at, spvar->inst_offset);
3920 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3921 mips_lw (code, mips_ra, mips_at, 0);
3923 mips_jr (code, mips_ra);
3927 case OP_ENDFINALLY: {
3928 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3929 g_assert (spvar->inst_basereg != mips_sp);
3930 code = emit_unreserve_param_area (cfg, code);
3931 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3932 mips_jalr (code, mips_t9, mips_ra);
3936 case OP_CALL_HANDLER:
3937 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3938 mips_lui (code, mips_t9, mips_zero, 0);
3939 mips_addiu (code, mips_t9, mips_t9, 0);
3940 mips_jalr (code, mips_t9, mips_ra);
3942 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3943 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3946 ins->inst_c0 = code - cfg->native_code;
3949 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3950 if (cfg->arch.long_branch) {
3951 mips_lui (code, mips_at, mips_zero, 0);
3952 mips_addiu (code, mips_at, mips_at, 0);
3953 mips_jr (code, mips_at);
3957 mips_beq (code, mips_zero, mips_zero, 0);
3962 mips_jr (code, ins->sreg1);
3968 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3969 if (offset > (cfg->code_size - max_len - 16)) {
3970 cfg->code_size += max_len;
3971 cfg->code_size *= 2;
3972 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3973 code = cfg->native_code + offset;
3975 g_assert (ins->sreg1 != -1);
3976 mips_sll (code, mips_at, ins->sreg1, 2);
3977 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3978 MIPS_MOVE (code, mips_t8, mips_ra);
3979 mips_bgezal (code, mips_zero, 1); /* bal */
3981 mips_addu (code, mips_t9, mips_ra, mips_at);
3982 /* Table is 16 or 20 bytes from target of bal above */
3983 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3984 MIPS_MOVE (code, mips_ra, mips_t8);
3985 mips_lw (code, mips_t9, mips_t9, 20);
3988 mips_lw (code, mips_t9, mips_t9, 16);
3989 mips_jalr (code, mips_t9, mips_t8);
3991 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3992 mips_emit32 (code, 0xfefefefe);
3997 mips_addiu (code, ins->dreg, mips_zero, 1);
3998 mips_beq (code, mips_at, mips_zero, 2);
4000 MIPS_MOVE (code, ins->dreg, mips_zero);
4006 mips_addiu (code, ins->dreg, mips_zero, 1);
4007 mips_bltz (code, mips_at, 2);
4009 MIPS_MOVE (code, ins->dreg, mips_zero);
4015 mips_addiu (code, ins->dreg, mips_zero, 1);
4016 mips_bgtz (code, mips_at, 2);
4018 MIPS_MOVE (code, ins->dreg, mips_zero);
4021 case OP_MIPS_COND_EXC_EQ:
4022 case OP_MIPS_COND_EXC_GE:
4023 case OP_MIPS_COND_EXC_GT:
4024 case OP_MIPS_COND_EXC_LE:
4025 case OP_MIPS_COND_EXC_LT:
4026 case OP_MIPS_COND_EXC_NE_UN:
4027 case OP_MIPS_COND_EXC_GE_UN:
4028 case OP_MIPS_COND_EXC_GT_UN:
4029 case OP_MIPS_COND_EXC_LE_UN:
4030 case OP_MIPS_COND_EXC_LT_UN:
4032 case OP_MIPS_COND_EXC_OV:
4033 case OP_MIPS_COND_EXC_NO:
4034 case OP_MIPS_COND_EXC_C:
4035 case OP_MIPS_COND_EXC_NC:
4037 case OP_MIPS_COND_EXC_IEQ:
4038 case OP_MIPS_COND_EXC_IGE:
4039 case OP_MIPS_COND_EXC_IGT:
4040 case OP_MIPS_COND_EXC_ILE:
4041 case OP_MIPS_COND_EXC_ILT:
4042 case OP_MIPS_COND_EXC_INE_UN:
4043 case OP_MIPS_COND_EXC_IGE_UN:
4044 case OP_MIPS_COND_EXC_IGT_UN:
4045 case OP_MIPS_COND_EXC_ILE_UN:
4046 case OP_MIPS_COND_EXC_ILT_UN:
4048 case OP_MIPS_COND_EXC_IOV:
4049 case OP_MIPS_COND_EXC_INO:
4050 case OP_MIPS_COND_EXC_IC:
4051 case OP_MIPS_COND_EXC_INC: {
4055 /* If the condition is true, raise the exception */
4057 /* need to reverse test to skip around exception raising */
4059 /* For the moment, branch around a branch to avoid reversing
4062 /* Remember, an unpatched branch to 0 branches to the delay slot */
4063 switch (ins->opcode) {
4064 case OP_MIPS_COND_EXC_EQ:
4065 throw = (guint32 *)(void *)code;
4066 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4070 case OP_MIPS_COND_EXC_NE_UN:
4071 throw = (guint32 *)(void *)code;
4072 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4076 case OP_MIPS_COND_EXC_LE_UN:
4077 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4078 throw = (guint32 *)(void *)code;
4079 mips_beq (code, mips_at, mips_zero, 0);
4083 case OP_MIPS_COND_EXC_GT:
4084 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4085 throw = (guint32 *)(void *)code;
4086 mips_bne (code, mips_at, mips_zero, 0);
4090 case OP_MIPS_COND_EXC_GT_UN:
4091 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4092 throw = (guint32 *)(void *)code;
4093 mips_bne (code, mips_at, mips_zero, 0);
4097 case OP_MIPS_COND_EXC_LT:
4098 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4099 throw = (guint32 *)(void *)code;
4100 mips_bne (code, mips_at, mips_zero, 0);
4104 case OP_MIPS_COND_EXC_LT_UN:
4105 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4106 throw = (guint32 *)(void *)code;
4107 mips_bne (code, mips_at, mips_zero, 0);
4112 /* Not yet implemented */
4113 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4114 g_assert_not_reached ();
4116 skip = (guint32 *)(void *)code;
4117 mips_beq (code, mips_zero, mips_zero, 0);
4119 mips_patch (throw, (guint32)code);
4120 code = mips_emit_exc_by_name (code, ins->inst_p1);
4121 mips_patch (skip, (guint32)code);
4122 cfg->bb_exit->max_offset += 24;
4131 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4134 /* floating point opcodes */
4137 if (((guint32)ins->inst_p0) & (1 << 15))
4138 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4140 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4141 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4143 mips_load_const (code, mips_at, ins->inst_p0);
4144 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4145 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4149 if (((guint32)ins->inst_p0) & (1 << 15))
4150 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4152 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4153 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4154 #if PROMOTE_R4_TO_R8
4155 mips_cvtds (code, ins->dreg, ins->dreg);
4158 case OP_STORER8_MEMBASE_REG:
4159 if (mips_is_imm16 (ins->inst_offset)) {
4160 #if _MIPS_SIM == _ABIO32
4161 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4162 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4163 #elif _MIPS_SIM == _ABIN32
4164 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4167 mips_load_const (code, mips_at, ins->inst_offset);
4168 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4169 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4170 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4173 case OP_LOADR8_MEMBASE:
4174 if (mips_is_imm16 (ins->inst_offset)) {
4175 #if _MIPS_SIM == _ABIO32
4176 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4177 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4178 #elif _MIPS_SIM == _ABIN32
4179 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4182 mips_load_const (code, mips_at, ins->inst_offset);
4183 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4184 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4185 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4188 case OP_STORER4_MEMBASE_REG:
4189 g_assert (mips_is_imm16 (ins->inst_offset));
4190 #if PROMOTE_R4_TO_R8
4191 /* Need to convert ins->sreg1 to single-precision first */
4192 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4193 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4195 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4199 g_assert (mips_is_imm16 (ins->inst_offset));
4200 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4202 case OP_LOADR4_MEMBASE:
4203 g_assert (mips_is_imm16 (ins->inst_offset));
4204 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4205 #if PROMOTE_R4_TO_R8
4206 /* Convert to double precision in place */
4207 mips_cvtds (code, ins->dreg, ins->dreg);
4210 case OP_LOADR4_MEMINDEX:
4211 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4212 mips_lwc1 (code, ins->dreg, mips_at, 0);
4214 case OP_LOADR8_MEMINDEX:
4215 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4216 #if _MIPS_SIM == _ABIO32
4217 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4218 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4219 #elif _MIPS_SIM == _ABIN32
4220 mips_ldc1 (code, ins->dreg, mips_at, 0);
4223 case OP_STORER4_MEMINDEX:
4224 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4225 #if PROMOTE_R4_TO_R8
4226 /* Need to convert ins->sreg1 to single-precision first */
4227 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4228 mips_swc1 (code, mips_ftemp, mips_at, 0);
4230 mips_swc1 (code, ins->sreg1, mips_at, 0);
4233 case OP_STORER8_MEMINDEX:
4234 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4235 #if _MIPS_SIM == _ABIO32
4236 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4237 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4238 #elif _MIPS_SIM == _ABIN32
4239 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4242 case OP_ICONV_TO_R_UN: {
4243 static const guint64 adjust_val = 0x41F0000000000000ULL;
4245 /* convert unsigned int to double */
4246 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4247 mips_bgez (code, ins->sreg1, 5);
4248 mips_cvtdw (code, ins->dreg, mips_ftemp);
4250 mips_load (code, mips_at, (guint32) &adjust_val);
4251 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4252 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4253 /* target is here */
4256 case OP_ICONV_TO_R4:
4257 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4258 mips_cvtsw (code, ins->dreg, mips_ftemp);
4259 mips_cvtds (code, ins->dreg, ins->dreg);
4261 case OP_ICONV_TO_R8:
4262 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4263 mips_cvtdw (code, ins->dreg, mips_ftemp);
4265 case OP_FCONV_TO_I1:
4266 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4268 case OP_FCONV_TO_U1:
4269 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4271 case OP_FCONV_TO_I2:
4272 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4274 case OP_FCONV_TO_U2:
4275 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4277 case OP_FCONV_TO_I4:
4279 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4281 case OP_FCONV_TO_U4:
4283 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4286 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4289 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4292 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4295 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4298 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4301 mips_fnegd (code, ins->dreg, ins->sreg1);
4304 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4305 mips_addiu (code, ins->dreg, mips_zero, 1);
4306 mips_fbtrue (code, 2);
4308 MIPS_MOVE (code, ins->dreg, mips_zero);
4311 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4312 mips_addiu (code, ins->dreg, mips_zero, 1);
4313 mips_fbtrue (code, 2);
4315 MIPS_MOVE (code, ins->dreg, mips_zero);
4318 /* Less than, or Unordered */
4319 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4320 mips_addiu (code, ins->dreg, mips_zero, 1);
4321 mips_fbtrue (code, 2);
4323 MIPS_MOVE (code, ins->dreg, mips_zero);
4326 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4327 MIPS_MOVE (code, ins->dreg, mips_zero);
4328 mips_fbtrue (code, 2);
4330 mips_addiu (code, ins->dreg, mips_zero, 1);
4333 /* Greater than, or Unordered */
4334 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4335 MIPS_MOVE (code, ins->dreg, mips_zero);
4336 mips_fbtrue (code, 2);
4338 mips_addiu (code, ins->dreg, mips_zero, 1);
4343 case OP_MIPS_FBLT_UN:
4345 case OP_MIPS_FBGT_UN:
4347 case OP_MIPS_FBGE_UN:
4349 case OP_MIPS_FBLE_UN: {
4351 gboolean is_true = TRUE, is_ordered = FALSE;
4352 guint32 *buf = NULL;
4354 switch (ins->opcode) {
4368 case OP_MIPS_FBLT_UN:
4369 cond = MIPS_FPU_ULT;
4377 case OP_MIPS_FBGT_UN:
4378 cond = MIPS_FPU_OLE;
4386 case OP_MIPS_FBGE_UN:
4387 cond = MIPS_FPU_OLT;
4391 cond = MIPS_FPU_OLE;
4395 case OP_MIPS_FBLE_UN:
4396 cond = MIPS_FPU_ULE;
4400 g_assert_not_reached ();
4404 /* Skip the check if unordered */
4405 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4407 buf = (guint32*)code;
4408 mips_fbtrue (code, 0);
4412 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4414 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4416 mips_fbtrue (code, 0);
4418 mips_fbfalse (code, 0);
4422 mips_patch (buf, (guint32)code);
4426 guint32 *branch_patch;
4428 mips_mfc1 (code, mips_at, ins->sreg1+1);
4429 mips_srl (code, mips_at, mips_at, 16+4);
4430 mips_andi (code, mips_at, mips_at, 2047);
4431 mips_addiu (code, mips_at, mips_at, -2047);
4433 branch_patch = (guint32 *)(void *)code;
4434 mips_bne (code, mips_at, mips_zero, 0);
4437 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4438 mips_patch (branch_patch, (guint32)code);
4439 mips_fmovd (code, ins->dreg, ins->sreg1);
4443 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4444 mips_load (code, ins->dreg, 0x0f0f0f0f);
4449 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4450 g_assert_not_reached ();
4453 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4454 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4455 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4456 g_assert_not_reached ();
4462 last_offset = offset;
4465 cfg->code_len = code - cfg->native_code;
4469 mono_arch_register_lowlevel_calls (void)
4474 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4476 MonoJumpInfo *patch_info;
4478 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4479 unsigned char *ip = patch_info->ip.i + code;
4480 const unsigned char *target = NULL;
4482 switch (patch_info->type) {
4483 case MONO_PATCH_INFO_IP:
4484 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4486 case MONO_PATCH_INFO_SWITCH: {
4487 gpointer *table = (gpointer *)patch_info->data.table->table;
4490 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4492 for (i = 0; i < patch_info->data.table->table_size; i++) {
4493 table [i] = (int)patch_info->data.table->table [i] + code;
4497 case MONO_PATCH_INFO_METHODCONST:
4498 case MONO_PATCH_INFO_CLASS:
4499 case MONO_PATCH_INFO_IMAGE:
4500 case MONO_PATCH_INFO_FIELD:
4501 case MONO_PATCH_INFO_VTABLE:
4502 case MONO_PATCH_INFO_IID:
4503 case MONO_PATCH_INFO_SFLDA:
4504 case MONO_PATCH_INFO_LDSTR:
4505 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4506 case MONO_PATCH_INFO_LDTOKEN:
4507 case MONO_PATCH_INFO_R4:
4508 case MONO_PATCH_INFO_R8:
4509 /* from OP_AOTCONST : lui + addiu */
4510 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4511 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4514 case MONO_PATCH_INFO_EXC_NAME:
4515 g_assert_not_reached ();
4516 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4519 case MONO_PATCH_INFO_NONE:
4520 /* everything is dealt with at epilog output time */
4523 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4524 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4533 mono_trace_lmf_prolog (MonoLMF *new_lmf)
4539 mono_trace_lmf_epilog (MonoLMF *old_lmf)
4545 * Allow tracing to work with this interface (with an optional argument)
4547 * This code is expected to be inserted just after the 'real' prolog code,
4548 * and before the first basic block. We need to allocate a 2nd, temporary
4549 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4553 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4556 int offset = cfg->arch.tracing_offset;
4562 /* For N32, need to know for each stack slot if it's an integer
4563 * or float argument, and save/restore the appropriate register
4565 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4566 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4567 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4568 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4569 #if _MIPS_SIM == _ABIN32
4570 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4571 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4572 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4573 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4576 mips_load_const (code, mips_a0, cfg->method);
4577 mips_addiu (code, mips_a1, mips_sp, offset);
4578 mips_call (code, mips_t9, func);
4580 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4581 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4582 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4583 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4584 #if _MIPS_SIM == _ABIN32
4585 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4586 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4587 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4588 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4598 mips_adjust_stackframe(MonoCompile *cfg)
4601 int delta, threshold, i;
4602 MonoMethodSignature *sig;
4605 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4608 /* adjust cfg->stack_offset for account for down-spilling */
4609 cfg->stack_offset += SIZEOF_REGISTER;
4611 /* re-align cfg->stack_offset if needed (due to var spilling) */
4612 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4613 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4614 if (cfg->verbose_level > 2) {
4615 g_print ("mips_adjust_stackframe:\n");
4616 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4618 threshold = cfg->arch.local_alloc_offset;
4619 ra_offset = cfg->stack_offset - sizeof(gpointer);
4620 if (cfg->verbose_level > 2) {
4621 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4624 sig = mono_method_signature (cfg->method);
4625 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4626 cfg->vret_addr->inst_offset += delta;
4628 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4629 MonoInst *inst = cfg->args [i];
4631 inst->inst_offset += delta;
4635 * loads and stores based off the frame reg that (used to) lie
4636 * above the spill var area need to be increased by 'delta'
4637 * to make room for the spill vars.
4639 /* Need to find loads and stores to adjust that
4640 * are above where the spillvars were inserted, but
4641 * which are not the spillvar references themselves.
4643 * Idea - since all offsets from fp are positive, make
4644 * spillvar offsets negative to begin with so we can spot
4649 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4653 if (cfg->verbose_level > 2) {
4654 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4656 MONO_BB_FOR_EACH_INS (bb, ins) {
4660 if (cfg->verbose_level > 2) {
4661 mono_print_ins_index (ins_cnt, ins);
4663 /* The == mips_sp tests catch FP spills */
4664 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4665 (ins->inst_basereg == mips_sp))) {
4666 switch (ins->opcode) {
4667 case OP_LOADI8_MEMBASE:
4668 case OP_LOADR8_MEMBASE:
4675 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4676 (ins->dreg == mips_sp))) {
4677 switch (ins->opcode) {
4678 case OP_STOREI8_MEMBASE_REG:
4679 case OP_STORER8_MEMBASE_REG:
4680 case OP_STOREI8_MEMBASE_IMM:
4688 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4691 if (ins->inst_c0 >= threshold) {
4692 ins->inst_c0 += delta;
4693 if (cfg->verbose_level > 2) {
4695 mono_print_ins_index (ins_cnt, ins);
4698 else if (ins->inst_c0 < 0) {
4699 /* Adj_c0 holds the size of the datatype. */
4700 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4701 if (cfg->verbose_level > 2) {
4703 mono_print_ins_index (ins_cnt, ins);
4706 g_assert (ins->inst_c0 != ra_offset);
4709 if (ins->inst_imm >= threshold) {
4710 ins->inst_imm += delta;
4711 if (cfg->verbose_level > 2) {
4713 mono_print_ins_index (ins_cnt, ins);
4716 g_assert (ins->inst_c0 != ra_offset);
4726 * Stack frame layout:
4728 * ------------------- sp + cfg->stack_usage + cfg->param_area
4729 * param area incoming
4730 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4732 * ------------------- sp + cfg->stack_usage
4734 * ------------------- sp + cfg->stack_usage-4
4736 * ------------------- sp +
4737 * MonoLMF structure optional
4738 * ------------------- sp + cfg->arch.lmf_offset
4739 * saved registers s0-s8
4740 * ------------------- sp + cfg->arch.iregs_offset
4742 * ------------------- sp + cfg->param_area
4743 * param area outgoing
4744 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4746 * ------------------- sp
4750 mono_arch_emit_prolog (MonoCompile *cfg)
4752 MonoMethod *method = cfg->method;
4753 MonoMethodSignature *sig;
4755 int alloc_size, pos, i;
4756 int alloc2_size = 0;
4760 guint32 iregs_to_save = 0;
4762 guint32 fregs_to_save = 0;
4765 /* lmf_offset is the offset of the LMF from our stack pointer. */
4766 guint32 lmf_offset = cfg->arch.lmf_offset;
4770 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4774 cfg->flags |= MONO_CFG_HAS_CALLS;
4776 sig = mono_method_signature (method);
4777 cfg->code_size = 768 + sig->param_count * 20;
4778 code = cfg->native_code = g_malloc (cfg->code_size);
4781 #if _MIPS_SIM == _ABIO32
4782 cfg->arch.tracing_offset = cfg->stack_offset;
4783 #elif _MIPS_SIM == _ABIN32
4784 /* no stack slots by default for argument regs, reserve a special block */
4785 cfg->arch.tracing_offset = cfg->stack_offset;
4786 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4790 /* adjust stackframe assignments for spillvars if needed */
4791 mips_adjust_stackframe (cfg);
4793 /* Offset between current sp and the CFA */
4795 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4797 /* stack_offset should not be changed here. */
4798 alloc_size = cfg->stack_offset;
4799 cfg->stack_usage = alloc_size;
4802 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4804 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4808 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4810 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4811 fregs_to_save |= (fregs_to_save << 1);
4814 /* If the stack size is too big, save 1024 bytes to start with
4815 * so the prologue can use imm16(reg) addressing, then allocate
4816 * the rest of the frame.
4818 if (alloc_size > ((1 << 15) - 1024)) {
4819 alloc2_size = alloc_size - 1024;
4823 g_assert (mips_is_imm16 (-alloc_size));
4824 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4825 cfa_offset = alloc_size;
4826 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4829 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4830 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4831 if (mips_is_imm16(offset))
4832 mips_sw (code, mips_ra, mips_sp, offset);
4834 g_assert_not_reached ();
4836 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4837 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4840 /* XXX - optimize this later to not save all regs if LMF constructed */
4841 pos = cfg->arch.iregs_offset - alloc2_size;
4843 if (iregs_to_save) {
4844 /* save used registers in own stack frame (at pos) */
4845 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4846 if (iregs_to_save & (1 << i)) {
4847 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4848 g_assert (mips_is_imm16(pos));
4849 MIPS_SW (code, i, mips_sp, pos);
4850 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4851 pos += SIZEOF_REGISTER;
4856 if (method->save_lmf) {
4857 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4858 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4859 g_assert (mips_is_imm16(offset));
4860 MIPS_SW (code, i, mips_sp, offset);
4866 /* Save float registers */
4867 if (fregs_to_save) {
4868 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4869 if (fregs_to_save & (1 << i)) {
4870 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4871 g_assert (mips_is_imm16(pos));
4872 mips_swc1 (code, i, mips_sp, pos);
4873 pos += sizeof (gulong);
4878 if (method->save_lmf) {
4879 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4880 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4881 g_assert (mips_is_imm16(offset));
4882 mips_swc1 (code, i, mips_sp, offset);
4887 if (cfg->frame_reg != mips_sp) {
4888 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4889 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4891 if (method->save_lmf) {
4892 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4893 g_assert (mips_is_imm16(offset));
4894 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4899 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
4900 * to the t* registers, which would be clobbered by the instrumentation calls.
4903 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4907 /* load arguments allocated to register from the stack */
4910 cinfo = calculate_sizes (sig, sig->pinvoke);
4912 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4913 ArgInfo *ainfo = &cinfo->ret;
4914 inst = cfg->vret_addr;
4915 if (inst->opcode == OP_REGVAR)
4916 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4917 else if (mips_is_imm16 (inst->inst_offset)) {
4918 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4920 mips_load_const (code, mips_at, inst->inst_offset);
4921 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4922 mips_sw (code, ainfo->reg, mips_at, 0);
4925 /* Keep this in sync with emit_load_volatile_arguments */
4926 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4927 ArgInfo *ainfo = cinfo->args + i;
4928 inst = cfg->args [pos];
4930 if (cfg->verbose_level > 2)
4931 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4932 if (inst->opcode == OP_REGVAR) {
4933 /* Argument ends up in a register */
4934 if (ainfo->regtype == RegTypeGeneral)
4935 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4936 else if (ainfo->regtype == RegTypeFP) {
4937 g_assert_not_reached();
4939 ppc_fmr (code, inst->dreg, ainfo->reg);
4942 else if (ainfo->regtype == RegTypeBase) {
4943 int offset = cfg->stack_usage + ainfo->offset;
4944 g_assert (mips_is_imm16(offset));
4945 mips_lw (code, inst->dreg, mips_sp, offset);
4947 g_assert_not_reached ();
4949 if (cfg->verbose_level > 2)
4950 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4952 /* Argument ends up on the stack */
4953 if (ainfo->regtype == RegTypeGeneral) {
4955 /* Incoming parameters should be above this frame */
4956 if (cfg->verbose_level > 2)
4957 g_print ("stack slot at %d of %d+%d\n",
4958 inst->inst_offset, alloc_size, alloc2_size);
4959 /* g_assert (inst->inst_offset >= alloc_size); */
4960 g_assert (inst->inst_basereg == mips_fp);
4961 basereg_offset = inst->inst_offset - alloc2_size;
4962 g_assert (mips_is_imm16 (basereg_offset));
4963 switch (ainfo->size) {
4965 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4968 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4972 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4975 #if (SIZEOF_REGISTER == 4)
4976 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
4977 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
4978 #elif (SIZEOF_REGISTER == 8)
4979 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4983 g_assert_not_reached ();
4986 } else if (ainfo->regtype == RegTypeBase) {
4988 * Argument comes in on the stack, and ends up on the stack
4989 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4990 * 8 and 16 bit quantities. Shorten them in place.
4992 g_assert (mips_is_imm16 (inst->inst_offset));
4993 switch (ainfo->size) {
4995 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4996 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4999 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5000 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5007 g_assert_not_reached ();
5009 } else if (ainfo->regtype == RegTypeFP) {
5010 g_assert (mips_is_imm16 (inst->inst_offset));
5011 g_assert (mips_is_imm16 (inst->inst_offset+4));
5012 if (ainfo->size == 8) {
5013 #if _MIPS_SIM == _ABIO32
5014 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5015 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5016 #elif _MIPS_SIM == _ABIN32
5017 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5020 else if (ainfo->size == 4)
5021 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5023 g_assert_not_reached ();
5024 } else if (ainfo->regtype == RegTypeStructByVal) {
5026 int doffset = inst->inst_offset;
5028 g_assert (mips_is_imm16 (inst->inst_offset));
5029 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5030 /* Push the argument registers into their stack slots */
5031 for (i = 0; i < ainfo->size; ++i) {
5032 g_assert (mips_is_imm16(doffset));
5033 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5034 doffset += SIZEOF_REGISTER;
5036 } else if (ainfo->regtype == RegTypeStructByAddr) {
5037 g_assert (mips_is_imm16 (inst->inst_offset));
5038 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5039 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5041 g_assert_not_reached ();
5046 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
5047 mips_load_const (code, mips_a0, cfg->domain);
5048 mips_call (code, mips_t9, (gpointer)mono_jit_thread_attach);
5052 if (method->save_lmf) {
5053 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5054 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5056 if (lmf_pthread_key != -1) {
5057 g_assert_not_reached();
5059 emit_tls_access (code, mips_temp, lmf_pthread_key);
5061 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5062 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5063 g_assert (mips_is_imm16(offset));
5064 mips_addiu (code, mips_a0, mips_temp, offset);
5067 /* This can/will clobber the a0-a3 registers */
5068 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5071 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5072 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5073 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5074 /* new_lmf->previous_lmf = *lmf_addr */
5075 mips_lw (code, mips_at, mips_v0, 0);
5076 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5077 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5078 /* *(lmf_addr) = sp + lmf_offset */
5079 g_assert (mips_is_imm16(lmf_offset));
5080 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5081 mips_sw (code, mips_at, mips_v0, 0);
5083 /* save method info */
5084 mips_load_const (code, mips_at, method);
5085 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5086 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5087 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
5088 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
5090 /* save the current IP */
5091 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5092 mips_load_const (code, mips_at, 0x01010101);
5093 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5097 /* The CFA is fp now, so this doesn't need unwind info */
5098 if (mips_is_imm16 (-alloc2_size)) {
5099 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5102 mips_load_const (code, mips_at, -alloc2_size);
5103 mips_addu (code, mips_sp, mips_sp, mips_at);
5105 if (cfg->frame_reg != mips_sp)
5106 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5107 alloc_size += alloc2_size;
5110 cfg->code_len = code - cfg->native_code;
5111 g_assert (cfg->code_len < cfg->code_size);
5126 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5129 int save_mode = SAVE_NONE;
5131 MonoMethod *method = cfg->method;
5132 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5133 int save_offset = MIPS_STACK_PARAM_OFFSET;
5135 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5137 offset = code - cfg->native_code;
5138 /* we need about 16 instructions */
5139 if (offset > (cfg->code_size - 16 * 4)) {
5140 cfg->code_size *= 2;
5141 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5142 code = cfg->native_code + offset;
5147 case MONO_TYPE_VOID:
5148 /* special case string .ctor icall */
5149 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5150 save_mode = SAVE_ONE;
5152 save_mode = SAVE_NONE;
5156 save_mode = SAVE_FP;
5158 case MONO_TYPE_VALUETYPE:
5159 save_mode = SAVE_STRUCT;
5163 #if SIZEOF_REGISTER == 4
5164 save_mode = SAVE_TWO;
5165 #elif SIZEOF_REGISTER == 8
5166 save_mode = SAVE_ONE;
5170 save_mode = SAVE_ONE;
5174 mips_addiu (code, mips_sp, mips_sp, -32);
5175 g_assert (mips_is_imm16(save_offset));
5176 switch (save_mode) {
5178 mips_sw (code, mips_v0, mips_sp, save_offset);
5179 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5180 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5181 if (enable_arguments) {
5182 MIPS_MOVE (code, mips_a1, mips_v0);
5183 MIPS_MOVE (code, mips_a2, mips_v1);
5187 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5188 if (enable_arguments) {
5189 MIPS_MOVE (code, mips_a1, mips_v0);
5193 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5194 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5195 mips_lw (code, mips_a0, mips_sp, save_offset);
5196 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5197 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5204 mips_load_const (code, mips_a0, cfg->method);
5205 mips_call (code, mips_t9, func);
5207 switch (save_mode) {
5209 mips_lw (code, mips_v0, mips_sp, save_offset);
5210 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5211 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5214 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5217 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5224 mips_addiu (code, mips_sp, mips_sp, 32);
5231 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5233 MonoMethod *method = cfg->method;
5235 int max_epilog_size = 16 + 20*4;
5236 int alloc2_size = 0;
5237 guint32 iregs_to_restore;
5239 guint32 fregs_to_restore;
5243 if (cfg->method->save_lmf)
5244 max_epilog_size += 128;
5247 if (mono_jit_trace_calls != NULL)
5248 max_epilog_size += 50;
5250 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5251 max_epilog_size += 50;
5254 pos = code - cfg->native_code;
5255 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5256 cfg->code_size *= 2;
5257 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5258 cfg->stat_code_reallocs++;
5262 * Keep in sync with OP_JMP
5265 code = cfg->native_code + pos;
5267 code = cfg->native_code + cfg->code_len;
5269 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5270 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5272 if (cfg->frame_reg != mips_sp) {
5273 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5275 /* If the stack frame is really large, deconstruct it in two steps */
5276 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5277 alloc2_size = cfg->stack_usage - 1024;
5278 /* partially deconstruct the stack */
5279 mips_load_const (code, mips_at, alloc2_size);
5280 mips_addu (code, mips_sp, mips_sp, mips_at);
5282 pos = cfg->arch.iregs_offset - alloc2_size;
5284 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5286 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5288 if (iregs_to_restore) {
5289 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5290 if (iregs_to_restore & (1 << i)) {
5291 g_assert (mips_is_imm16(pos));
5292 MIPS_LW (code, i, mips_sp, pos);
5293 pos += SIZEOF_REGISTER;
5300 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5302 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5303 fregs_to_restore |= (fregs_to_restore << 1);
5305 if (fregs_to_restore) {
5306 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5307 if (fregs_to_restore & (1 << i)) {
5308 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5309 g_assert (mips_is_imm16(pos));
5310 mips_lwc1 (code, i, mips_sp, pos);
5317 /* Unlink the LMF if necessary */
5318 if (method->save_lmf) {
5319 int lmf_offset = cfg->arch.lmf_offset;
5321 /* t0 = current_lmf->previous_lmf */
5322 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5323 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5325 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5326 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5327 /* (*lmf_addr) = previous_lmf */
5328 mips_sw (code, mips_temp, mips_t1, 0);
5332 /* Restore the fp */
5333 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5336 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5337 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5338 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5340 /* Restore the stack pointer */
5341 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5342 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5344 /* Caller will emit either return or tail-call sequence */
5346 cfg->code_len = code - cfg->native_code;
5348 g_assert (cfg->code_len < cfg->code_size);
5353 mono_arch_emit_epilog (MonoCompile *cfg)
5357 code = mono_arch_emit_epilog_sub (cfg, NULL);
5359 mips_jr (code, mips_ra);
5362 cfg->code_len = code - cfg->native_code;
5364 g_assert (cfg->code_len < cfg->code_size);
5367 /* remove once throw_exception_by_name is eliminated */
5370 exception_id_by_name (const char *name)
5372 if (strcmp (name, "IndexOutOfRangeException") == 0)
5373 return MONO_EXC_INDEX_OUT_OF_RANGE;
5374 if (strcmp (name, "OverflowException") == 0)
5375 return MONO_EXC_OVERFLOW;
5376 if (strcmp (name, "ArithmeticException") == 0)
5377 return MONO_EXC_ARITHMETIC;
5378 if (strcmp (name, "DivideByZeroException") == 0)
5379 return MONO_EXC_DIVIDE_BY_ZERO;
5380 if (strcmp (name, "InvalidCastException") == 0)
5381 return MONO_EXC_INVALID_CAST;
5382 if (strcmp (name, "NullReferenceException") == 0)
5383 return MONO_EXC_NULL_REF;
5384 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5385 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5386 if (strcmp (name, "ArgumentException") == 0)
5387 return MONO_EXC_ARGUMENT;
5388 g_error ("Unknown intrinsic exception %s\n", name);
5394 mono_arch_emit_exceptions (MonoCompile *cfg)
5397 MonoJumpInfo *patch_info;
5400 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5401 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5402 int max_epilog_size = 50;
5404 /* count the number of exception infos */
5407 * make sure we have enough space for exceptions
5408 * 24 is the simulated call to throw_exception_by_name
5410 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5412 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5413 i = exception_id_by_name (patch_info->data.target);
5414 g_assert (i < MONO_EXC_INTRINS_NUM);
5415 if (!exc_throw_found [i]) {
5416 max_epilog_size += 12;
5417 exc_throw_found [i] = TRUE;
5423 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5424 cfg->code_size *= 2;
5425 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5426 cfg->stat_code_reallocs++;
5429 code = cfg->native_code + cfg->code_len;
5431 /* add code to raise exceptions */
5432 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5433 switch (patch_info->type) {
5434 case MONO_PATCH_INFO_EXC: {
5436 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5438 i = exception_id_by_name (patch_info->data.target);
5439 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5440 if (!exc_throw_pos [i]) {
5443 exc_throw_pos [i] = code;
5444 //g_print ("exc: writing stub at %p\n", code);
5445 mips_load_const (code, mips_a0, patch_info->data.target);
5446 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5447 mips_load_const (code, mips_t9, addr);
5448 mips_jr (code, mips_t9);
5451 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5453 /* Turn into a Relative patch, pointing at code stub */
5454 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5455 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5457 g_assert_not_reached();
5467 cfg->code_len = code - cfg->native_code;
5469 g_assert (cfg->code_len < cfg->code_size);
5474 * Thread local storage support
5477 setup_tls_access (void)
5480 //guint32 *ins, *code;
5482 if (tls_mode == TLS_MODE_FAILED)
5485 if (g_getenv ("MONO_NO_TLS")) {
5486 tls_mode = TLS_MODE_FAILED;
5490 if (tls_mode == TLS_MODE_DETECT) {
5492 tls_mode = TLS_MODE_FAILED;
5496 ins = (guint32*)pthread_getspecific;
5497 /* uncond branch to the real method */
5498 if ((*ins >> 26) == 18) {
5500 val = (*ins & ~3) << 6;
5504 ins = (guint32*)val;
5506 ins = (guint32*) ((char*)ins + val);
5509 code = &cmplwi_1023;
5510 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5512 ppc_li (code, ppc_r4, 0x48);
5515 if (*ins == cmplwi_1023) {
5516 int found_lwz_284 = 0;
5517 for (ptk = 0; ptk < 20; ++ptk) {
5519 if (!*ins || *ins == blr_ins)
5521 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5526 if (!found_lwz_284) {
5527 tls_mode = TLS_MODE_FAILED;
5530 tls_mode = TLS_MODE_LTHREADS;
5531 } else if (*ins == li_0x48) {
5533 /* uncond branch to the real method */
5534 if ((*ins >> 26) == 18) {
5536 val = (*ins & ~3) << 6;
5540 ins = (guint32*)val;
5542 ins = (guint32*) ((char*)ins + val);
5545 ppc_li (code, ppc_r0, 0x7FF2);
5546 if (ins [1] == val) {
5547 /* Darwin on G4, implement */
5548 tls_mode = TLS_MODE_FAILED;
5552 ppc_mfspr (code, ppc_r3, 104);
5553 if (ins [1] != val) {
5554 tls_mode = TLS_MODE_FAILED;
5557 tls_mode = TLS_MODE_DARWIN_G5;
5560 tls_mode = TLS_MODE_FAILED;
5564 tls_mode = TLS_MODE_FAILED;
5569 if (monodomain_key == -1) {
5570 ptk = mono_domain_get_tls_key ();
5572 monodomain_key = ptk;
5574 if (lmf_pthread_key == -1) {
5575 ptk = mono_jit_tls_id;
5577 /*g_print ("MonoLMF at: %d\n", ptk);*/
5578 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5579 init_tls_failed = 1;
5582 lmf_pthread_key = ptk;
5585 if (monothread_key == -1) {
5586 ptk = mono_thread_get_tls_key ();
5588 monothread_key = ptk;
5589 /*g_print ("thread inited: %d\n", ptk);*/
5591 /*g_print ("thread not inited yet %d\n", ptk);*/
5597 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5599 setup_tls_access ();
5603 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5608 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5610 int this_dreg = mips_a0;
5613 this_dreg = mips_a1;
5615 /* add the this argument */
5616 if (this_reg != -1) {
5618 MONO_INST_NEW (cfg, this, OP_MOVE);
5619 this->type = this_type;
5620 this->sreg1 = this_reg;
5621 this->dreg = mono_alloc_ireg (cfg);
5622 mono_bblock_add_inst (cfg->cbb, this);
5623 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5628 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5629 vtarg->type = STACK_MP;
5630 vtarg->sreg1 = vt_reg;
5631 vtarg->dreg = mono_alloc_ireg (cfg);
5632 mono_bblock_add_inst (cfg->cbb, vtarg);
5633 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5638 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5640 MonoInst *ins = NULL;
5646 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5652 mono_arch_print_tree (MonoInst *tree, int arity)
5657 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5661 setup_tls_access ();
5662 if (monodomain_key == -1)
5665 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5666 ins->inst_offset = monodomain_key;
5671 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5673 return ctx->sc_regs [reg];
5676 #ifdef MONO_ARCH_HAVE_IMT
5678 #define ENABLE_WRONG_METHOD_CHECK 0
5680 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5681 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5683 #define LOADSTORE_SIZE 4
5684 #define JUMP_IMM_SIZE 16
5685 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5686 #define LOAD_CONST_SIZE 8
5687 #define JUMP_JR_SIZE 8
5690 * LOCKING: called with the domain lock held
5693 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5694 gpointer fail_tramp)
5698 guint8 *code, *start, *patch;
5700 for (i = 0; i < count; ++i) {
5701 MonoIMTCheckItem *item = imt_entries [i];
5703 if (item->is_equals) {
5704 if (item->check_target_idx) {
5705 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5706 if (item->has_target_code)
5707 item->chunk_size += LOAD_CONST_SIZE;
5709 item->chunk_size += LOADSTORE_SIZE;
5712 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5713 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5714 if (!item->has_target_code)
5715 item->chunk_size += LOADSTORE_SIZE;
5717 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5718 #if ENABLE_WRONG_METHOD_CHECK
5719 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5724 item->chunk_size += CMP_SIZE + BR_SIZE;
5725 imt_entries [item->check_target_idx]->compare_done = TRUE;
5727 size += item->chunk_size;
5729 /* the initial load of the vtable address */
5730 size += MIPS_LOAD_SEQUENCE_LENGTH;
5732 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5734 code = mono_domain_code_reserve (domain, size);
5740 * We need to save and restore r11 because it might be
5741 * used by the caller as the vtable register, so
5742 * clobbering it will trip up the magic trampoline.
5744 * FIXME: Get rid of this by making sure that r11 is
5745 * not used as the vtable register in interface calls.
5747 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5748 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5750 /* t7 points to the vtable */
5751 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5753 for (i = 0; i < count; ++i) {
5754 MonoIMTCheckItem *item = imt_entries [i];
5756 item->code_target = code;
5757 if (item->is_equals) {
5758 if (item->check_target_idx) {
5759 mips_load_const (code, mips_temp, (gsize)item->key);
5760 item->jmp_code = code;
5761 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5763 if (item->has_target_code) {
5764 mips_load_const (code, mips_t9,
5765 item->value.target_code);
5768 mips_lw (code, mips_t9, mips_t7,
5769 (sizeof (gpointer) * item->value.vtable_slot));
5771 mips_jr (code, mips_t9);
5775 mips_load_const (code, mips_temp, (gsize)item->key);
5777 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5779 if (item->has_target_code) {
5780 mips_load_const (code, mips_t9,
5781 item->value.target_code);
5784 mips_load_const (code, mips_at,
5785 & (vtable->vtable [item->value.vtable_slot]));
5786 mips_lw (code, mips_t9, mips_at, 0);
5788 mips_jr (code, mips_t9);
5790 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5791 mips_load_const (code, mips_at, fail_tramp);
5792 mips_lw (code, mips_t9, mips_at, 0);
5793 mips_jr (code, mips_t9);
5796 /* enable the commented code to assert on wrong method */
5797 #if ENABLE_WRONG_METHOD_CHECK
5798 ppc_load (code, ppc_r0, (guint32)item->key);
5799 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5801 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5803 mips_lw (code, mips_t9, mips_t7,
5804 (sizeof (gpointer) * item->value.vtable_slot));
5805 mips_jr (code, mips_t9);
5808 #if ENABLE_WRONG_METHOD_CHECK
5809 ppc_patch (patch, code);
5815 mips_load_const (code, mips_temp, (gulong)item->key);
5816 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5818 item->jmp_code = code;
5819 mips_beq (code, mips_temp, mips_zero, 0);
5823 /* patch the branches to get to the target items */
5824 for (i = 0; i < count; ++i) {
5825 MonoIMTCheckItem *item = imt_entries [i];
5826 if (item->jmp_code && item->check_target_idx) {
5827 mips_patch ((guint32 *)item->jmp_code,
5828 (guint32)imt_entries [item->check_target_idx]->code_target);
5833 mono_stats.imt_thunks_size += code - start;
5834 g_assert (code - start <= size);
5835 mono_arch_flush_icache (start, size);
5840 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5842 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5847 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5850 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5853 /* Soft Debug support */
5854 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5857 * mono_arch_set_breakpoint:
5859 * See mini-amd64.c for docs.
5862 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5865 guint32 addr = (guint32)bp_trigger_page;
5867 mips_load_const (code, mips_t9, addr);
5868 mips_lw (code, mips_t9, mips_t9, 0);
5870 mono_arch_flush_icache (ip, code - ip);
5874 * mono_arch_clear_breakpoint:
5876 * See mini-amd64.c for docs.
5879 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5887 mono_arch_flush_icache (ip, code - ip);
5891 * mono_arch_start_single_stepping:
5893 * See mini-amd64.c for docs.
5896 mono_arch_start_single_stepping (void)
5898 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5902 * mono_arch_stop_single_stepping:
5904 * See mini-amd64.c for docs.
5907 mono_arch_stop_single_stepping (void)
5909 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5913 * mono_arch_is_single_step_event:
5915 * See mini-amd64.c for docs.
5918 mono_arch_is_single_step_event (void *info, void *sigctx)
5920 siginfo_t* sinfo = (siginfo_t*) info;
5921 /* Sometimes the address is off by 4 */
5922 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5929 * mono_arch_is_breakpoint_event:
5931 * See mini-amd64.c for docs.
5934 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5936 siginfo_t* sinfo = (siginfo_t*) info;
5937 /* Sometimes the address is off by 4 */
5938 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5945 * mono_arch_skip_breakpoint:
5947 * See mini-amd64.c for docs.
5950 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5952 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5956 * mono_arch_skip_single_step:
5958 * See mini-amd64.c for docs.
5961 mono_arch_skip_single_step (MonoContext *ctx)
5963 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5967 * mono_arch_get_seq_point_info:
5969 * See mini-amd64.c for docs.
5972 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5978 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */