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>
21 #include <mono/utils/mono-hwcap-mips.h>
23 #include <mono/arch/mips/mips-codegen.h>
25 #include "mini-mips.h"
30 #define SAVE_FP_REGS 0
32 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
34 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
35 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
36 remember to update cpu-mips.md if you change this */
38 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
39 #define mips_call(c,D,v) do { \
40 guint32 _target = (guint32)(v); \
41 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
42 mips_load_const (c, D, _target); \
43 mips_jalr (c, D, mips_ra); \
46 mips_jumpl (c, _target >> 2); \
58 /* This mutex protects architecture specific caches */
59 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
60 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
61 static CRITICAL_SECTION mini_arch_mutex;
63 int mono_exc_esp_offset = 0;
64 static int tls_mode = TLS_MODE_DETECT;
65 static int lmf_pthread_key = -1;
66 static int monothread_key = -1;
67 static int monodomain_key = -1;
69 /* Whenever the host is little-endian */
70 static int little_endian;
71 /* Index of ms word/register */
72 static int ls_word_idx;
73 /* Index of ls word/register */
74 static int ms_word_idx;
75 /* Same for offsets */
76 static int ls_word_offset;
77 static int ms_word_offset;
80 * The code generated for sequence points reads from this location, which is
81 * made read-only when single stepping is enabled.
83 static gpointer ss_trigger_page;
85 /* Enabled breakpoints read from this trigger page */
86 static gpointer bp_trigger_page;
89 #define DEBUG(a) if (cfg->verbose_level > 1) a
95 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
97 code = mips_emit_exc_by_name (code, exc_name); \
98 cfg->bb_exit->max_offset += 16; \
102 #define emit_linuxthreads_tls(code,dreg,key) do {\
104 off1 = offsets_from_pthread_key ((key), &off2); \
105 g_assert_not_reached (); \
106 ppc_lwz ((code), (dreg), off1, ppc_r2); \
107 ppc_lwz ((code), (dreg), off2, (dreg)); \
111 #define emit_tls_access(code,dreg,key) do { \
112 switch (tls_mode) { \
113 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
114 default: g_assert_not_reached (); \
118 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
120 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
121 inst->type = STACK_R8; \
123 inst->inst_p0 = (void*)(addr); \
124 mono_bblock_add_inst (cfg->cbb, inst); \
127 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
128 || ((ins)->opcode == OP_ICOMPARE) \
129 || ((ins)->opcode == OP_LCOMPARE)))
130 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
131 || ((ins)->opcode == OP_ICOMPARE_IMM) \
132 || ((ins)->opcode == OP_LCOMPARE_IMM)))
134 #define INS_REWRITE(ins, op, _s1, _s2) do { \
137 ins->opcode = (op); \
142 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
144 ins->opcode = (op); \
146 ins->inst_imm = (_imm); \
150 typedef struct InstList InstList;
168 guint16 vtsize; /* in param area */
171 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
180 gboolean vtype_retaddr;
189 void patch_lui_addiu(guint32 *ip, guint32 val);
190 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
191 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
192 void mips_adjust_stackframe(MonoCompile *cfg);
193 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
194 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
197 /* Not defined in asm/cachectl.h */
198 int cacheflush(char *addr, int nbytes, int cache);
201 mono_arch_flush_icache (guint8 *code, gint size)
203 /* Linux/MIPS specific */
204 cacheflush ((char*)code, size, BCACHE);
208 mono_arch_flush_register_windows (void)
213 mono_arch_is_inst_imm (gint64 imm)
219 mips_emit_exc_by_name(guint8 *code, const char *name)
222 MonoClass *exc_class;
224 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
225 g_assert (exc_class);
227 mips_load_const (code, mips_a0, exc_class->type_token);
228 addr = mono_get_throw_corlib_exception ();
229 mips_call (code, mips_t9, addr);
235 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
237 if (mips_is_imm16 (v))
238 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
240 #if SIZEOF_REGISTER == 8
242 /* v is not a sign-extended 32-bit value */
243 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
244 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
245 mips_dsll (code, dreg, dreg, 16);
246 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
247 mips_dsll (code, dreg, dreg, 16);
248 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
252 if (((guint32)v) & (1 << 15)) {
253 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
256 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
258 if (((guint32)v) & 0xffff)
259 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
265 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
268 if (cfg->arch.long_branch) {
271 /* Invert test and emit branch around jump */
274 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
278 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
282 mips_bltz (code, ins->sreg1, br_offset);
286 mips_blez (code, ins->sreg1, br_offset);
290 mips_bgtz (code, ins->sreg1, br_offset);
294 mips_bgez (code, ins->sreg1, br_offset);
298 g_assert_not_reached ();
300 mono_add_patch_info (cfg, code - cfg->native_code,
301 MONO_PATCH_INFO_BB, ins->inst_true_bb);
302 mips_lui (code, mips_at, mips_zero, 0);
303 mips_addiu (code, mips_at, mips_at, 0);
304 mips_jr (code, mips_at);
308 mono_add_patch_info (cfg, code - cfg->native_code,
309 MONO_PATCH_INFO_BB, ins->inst_true_bb);
312 mips_beq (code, ins->sreg1, ins->sreg2, 0);
316 mips_bne (code, ins->sreg1, ins->sreg2, 0);
320 mips_bgez (code, ins->sreg1, 0);
324 mips_bgtz (code, ins->sreg1, 0);
328 mips_blez (code, ins->sreg1, 0);
332 mips_bltz (code, ins->sreg1, 0);
336 g_assert_not_reached ();
342 /* XXX - big-endian dependent? */
344 patch_lui_addiu(guint32 *ip, guint32 val)
346 guint16 *__lui_addiu = (guint16*)(void *)(ip);
349 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
350 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
353 if (((guint32)(val)) & (1 << 15))
354 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
356 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
357 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
358 mono_arch_flush_icache ((guint8 *)ip, 8);
363 mips_patch (guint32 *code, guint32 target)
366 guint32 op = ins >> 26;
367 guint32 diff, offset;
369 g_assert (trap_target != target);
370 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
372 case 0x00: /* jr ra */
373 if (ins == 0x3e00008)
375 g_assert_not_reached ();
379 g_assert (!(target & 0x03));
380 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
381 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
383 mono_arch_flush_icache ((guint8 *)code, 4);
385 case 0x01: /* BLTZ */
388 case 0x06: /* BLEZ */
389 case 0x07: /* BGTZ */
390 case 0x11: /* bc1t */
391 diff = target - (guint32)(code + 1);
392 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
393 g_assert (!(diff & 0x03));
394 offset = ((gint32)diff) >> 2;
395 if (((int)offset) != ((int)(short)offset))
396 g_assert (((int)offset) == ((int)(short)offset));
397 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
399 mono_arch_flush_icache ((guint8 *)code, 4);
401 case 0x0f: /* LUI / ADDIU pair */
402 g_assert ((code[1] >> 26) == 0x9);
403 patch_lui_addiu (code, target);
404 mono_arch_flush_icache ((guint8 *)code, 8);
408 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
409 g_assert_not_reached ();
415 offsets_from_pthread_key (guint32 key, int *offset2)
419 *offset2 = idx2 * sizeof (gpointer);
420 return 284 + idx1 * sizeof (gpointer);
424 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
427 mono_arch_regname (int reg) {
428 #if _MIPS_SIM == _ABIO32
429 static const char * rnames[] = {
430 "zero", "at", "v0", "v1",
431 "a0", "a1", "a2", "a3",
432 "t0", "t1", "t2", "t3",
433 "t4", "t5", "t6", "t7",
434 "s0", "s1", "s2", "s3",
435 "s4", "s5", "s6", "s7",
436 "t8", "t9", "k0", "k1",
437 "gp", "sp", "fp", "ra"
439 #elif _MIPS_SIM == _ABIN32
440 static const char * rnames[] = {
441 "zero", "at", "v0", "v1",
442 "a0", "a1", "a2", "a3",
443 "a4", "a5", "a6", "a7",
444 "t0", "t1", "t2", "t3",
445 "s0", "s1", "s2", "s3",
446 "s4", "s5", "s6", "s7",
447 "t8", "t9", "k0", "k1",
448 "gp", "sp", "fp", "ra"
451 if (reg >= 0 && reg < 32)
457 mono_arch_fregname (int reg) {
458 static const char * rnames[] = {
459 "f0", "f1", "f2", "f3",
460 "f4", "f5", "f6", "f7",
461 "f8", "f9", "f10", "f11",
462 "f12", "f13", "f14", "f15",
463 "f16", "f17", "f18", "f19",
464 "f20", "f21", "f22", "f23",
465 "f24", "f25", "f26", "f27",
466 "f28", "f29", "f30", "f31"
468 if (reg >= 0 && reg < 32)
473 /* this function overwrites at */
475 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
477 /* XXX write a loop, not an unrolled loop */
479 mips_lw (code, mips_at, sreg, soffset);
480 mips_sw (code, mips_at, dreg, doffset);
489 * mono_arch_get_argument_info:
490 * @csig: a method signature
491 * @param_count: the number of parameters to consider
492 * @arg_info: an array to store the result infos
494 * Gathers information on parameters such as size, alignment and
495 * padding. arg_info should be large enought to hold param_count + 1 entries.
497 * Returns the size of the activation frame.
500 mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
502 int k, frame_size = 0;
503 guint32 size, align, pad;
506 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
507 frame_size += sizeof (gpointer);
511 arg_info [0].offset = offset;
514 frame_size += sizeof (gpointer);
518 arg_info [0].size = frame_size;
520 for (k = 0; k < param_count; k++) {
521 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
523 /* ignore alignment for now */
526 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
527 arg_info [k].pad = pad;
529 arg_info [k + 1].pad = 0;
530 arg_info [k + 1].size = size;
532 arg_info [k + 1].offset = offset;
536 align = MONO_ARCH_FRAME_ALIGNMENT;
537 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
538 arg_info [k].pad = pad;
543 /* The delegate object plus 3 params */
544 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
547 get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
549 guint8 *code, *start;
552 start = code = mono_global_codeman_reserve (16);
554 /* Replace the this argument with the target */
555 mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
556 mips_lw (code, mips_a0, mips_a0, G_STRUCT_OFFSET (MonoDelegate, target));
557 mips_jr (code, mips_temp);
560 g_assert ((code - start) <= 16);
562 mono_arch_flush_icache (start, 16);
566 size = 16 + param_count * 4;
567 start = code = mono_global_codeman_reserve (size);
569 mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
570 /* slide down the arguments */
571 for (i = 0; i < param_count; ++i) {
572 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
574 mips_jr (code, mips_temp);
577 g_assert ((code - start) <= size);
579 mono_arch_flush_icache (start, size);
583 *code_size = code - start;
589 * mono_arch_get_delegate_invoke_impls:
591 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
595 mono_arch_get_delegate_invoke_impls (void)
602 code = get_delegate_invoke_impl (TRUE, 0, &code_len);
603 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
605 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
606 code = get_delegate_invoke_impl (FALSE, i, &code_len);
607 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
614 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
616 guint8 *code, *start;
618 /* FIXME: Support more cases */
619 if (MONO_TYPE_ISSTRUCT (sig->ret))
623 static guint8* cached = NULL;
624 mono_mini_arch_lock ();
626 mono_mini_arch_unlock ();
631 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
633 start = get_delegate_invoke_impl (TRUE, 0, NULL);
635 mono_mini_arch_unlock ();
638 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
641 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
643 for (i = 0; i < sig->param_count; ++i)
644 if (!mono_is_regsize_var (sig->params [i]))
647 mono_mini_arch_lock ();
648 code = cache [sig->param_count];
650 mono_mini_arch_unlock ();
655 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
656 start = mono_aot_get_trampoline (name);
659 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
661 cache [sig->param_count] = start;
662 mono_mini_arch_unlock ();
670 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
673 return (gpointer)regs [mips_a0];
677 * Initialize the cpu to execute managed code.
680 mono_arch_cpu_init (void)
682 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
691 ls_word_offset = ls_word_idx * 4;
692 ms_word_offset = ms_word_idx * 4;
696 * Initialize architecture specific code.
699 mono_arch_init (void)
701 InitializeCriticalSection (&mini_arch_mutex);
703 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
704 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
705 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
709 * Cleanup architecture specific code.
712 mono_arch_cleanup (void)
714 DeleteCriticalSection (&mini_arch_mutex);
718 * This function returns the optimizations supported on this cpu.
721 mono_arch_cpu_optimizations (guint32 *exclude_mask)
725 /* no mips-specific optimizations yet */
731 * This function test for all SIMD functions supported.
733 * Returns a bitmask corresponding to all supported versions.
737 mono_arch_cpu_enumerate_simd_versions (void)
739 /* SIMD is currently unimplemented */
744 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
749 for (i = 0; i < cfg->num_varinfo; i++) {
750 MonoInst *ins = cfg->varinfo [i];
751 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
754 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
757 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
760 /* we can only allocate 32 bit values */
761 if (mono_is_regsize_var (ins->inst_vtype)) {
762 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
763 g_assert (i == vmv->idx);
764 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
772 mono_arch_get_global_int_regs (MonoCompile *cfg)
776 regs = g_list_prepend (regs, (gpointer)mips_s0);
777 regs = g_list_prepend (regs, (gpointer)mips_s1);
778 regs = g_list_prepend (regs, (gpointer)mips_s2);
779 regs = g_list_prepend (regs, (gpointer)mips_s3);
780 regs = g_list_prepend (regs, (gpointer)mips_s4);
781 //regs = g_list_prepend (regs, (gpointer)mips_s5);
782 regs = g_list_prepend (regs, (gpointer)mips_s6);
783 regs = g_list_prepend (regs, (gpointer)mips_s7);
789 * mono_arch_regalloc_cost:
791 * Return the cost, in number of memory references, of the action of
792 * allocating the variable VMV into a register during global register
796 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
803 args_onto_stack (CallInfo *info)
805 g_assert (!info->on_stack);
806 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
807 info->on_stack = TRUE;
808 info->stack_size = MIPS_STACK_PARAM_OFFSET;
811 #if _MIPS_SIM == _ABIO32
813 * O32 calling convention version
817 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
818 /* First, see if we need to drop onto the stack */
819 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
820 args_onto_stack (info);
822 /* Now, place the argument */
823 if (info->on_stack) {
824 ainfo->storage = ArgOnStack;
825 ainfo->reg = mips_sp; /* in the caller */
826 ainfo->offset = info->stack_size;
829 ainfo->storage = ArgInIReg;
830 ainfo->reg = info->gr;
832 info->gr_passed = TRUE;
834 info->stack_size += 4;
838 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
839 /* First, see if we need to drop onto the stack */
840 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
841 args_onto_stack (info);
843 /* Now, place the argument */
844 if (info->on_stack) {
845 g_assert (info->stack_size % 4 == 0);
846 info->stack_size += (info->stack_size % 8);
848 ainfo->storage = ArgOnStack;
849 ainfo->reg = mips_sp; /* in the caller */
850 ainfo->offset = info->stack_size;
853 // info->gr must be a0 or a2
854 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
855 g_assert(info->gr <= MIPS_LAST_ARG_REG);
857 ainfo->storage = ArgInIReg;
858 ainfo->reg = info->gr;
860 info->gr_passed = TRUE;
862 info->stack_size += 8;
866 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
867 /* First, see if we need to drop onto the stack */
868 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
869 args_onto_stack (info);
871 /* Now, place the argument */
872 if (info->on_stack) {
873 ainfo->storage = ArgOnStack;
874 ainfo->reg = mips_sp; /* in the caller */
875 ainfo->offset = info->stack_size;
878 /* Only use FP regs for args if no int args passed yet */
879 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
880 ainfo->storage = ArgInFReg;
881 ainfo->reg = info->fr;
882 /* Even though it's a single-precision float, it takes up two FP regs */
884 /* FP and GP slots do not overlap */
888 /* Passing single-precision float arg in a GP register
889 * such as: func (0, 1.0, 2, 3);
890 * In this case, only one 'gr' register is consumed.
892 ainfo->storage = ArgInIReg;
893 ainfo->reg = info->gr;
896 info->gr_passed = TRUE;
899 info->stack_size += 4;
903 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
904 /* First, see if we need to drop onto the stack */
905 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
906 args_onto_stack (info);
908 /* Now, place the argument */
909 if (info->on_stack) {
910 g_assert(info->stack_size % 4 == 0);
911 info->stack_size += (info->stack_size % 8);
913 ainfo->storage = ArgOnStack;
914 ainfo->reg = mips_sp; /* in the caller */
915 ainfo->offset = info->stack_size;
918 /* Only use FP regs for args if no int args passed yet */
919 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
920 ainfo->storage = ArgInFReg;
921 ainfo->reg = info->fr;
923 /* FP and GP slots do not overlap */
927 // info->gr must be a0 or a2
928 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
929 g_assert(info->gr <= MIPS_LAST_ARG_REG);
931 ainfo->storage = ArgInIReg;
932 ainfo->reg = info->gr;
934 info->gr_passed = TRUE;
937 info->stack_size += 8;
939 #elif _MIPS_SIM == _ABIN32
941 * N32 calling convention version
945 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
946 /* First, see if we need to drop onto the stack */
947 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
948 args_onto_stack (info);
950 /* Now, place the argument */
951 if (info->on_stack) {
952 ainfo->storage = ArgOnStack;
953 ainfo->reg = mips_sp; /* in the caller */
954 ainfo->offset = info->stack_size;
955 info->stack_size += SIZEOF_REGISTER;
958 ainfo->storage = ArgInIReg;
959 ainfo->reg = info->gr;
961 info->gr_passed = TRUE;
966 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
967 /* First, see if we need to drop onto the stack */
968 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
969 args_onto_stack (info);
971 /* Now, place the argument */
972 if (info->on_stack) {
973 g_assert (info->stack_size % 4 == 0);
974 info->stack_size += (info->stack_size % 8);
976 ainfo->storage = ArgOnStack;
977 ainfo->reg = mips_sp; /* in the caller */
978 ainfo->offset = info->stack_size;
979 info->stack_size += SIZEOF_REGISTER;
982 g_assert (info->gr <= MIPS_LAST_ARG_REG);
984 ainfo->storage = ArgInIReg;
985 ainfo->reg = info->gr;
987 info->gr_passed = TRUE;
992 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
993 /* First, see if we need to drop onto the stack */
994 if (!info->on_stack) {
995 if (info->gr > MIPS_LAST_ARG_REG)
996 args_onto_stack (info);
997 else if (info->fr > MIPS_LAST_FPARG_REG)
998 args_onto_stack (info);
1001 /* Now, place the argument */
1002 if (info->on_stack) {
1003 ainfo->storage = ArgOnStack;
1004 ainfo->reg = mips_sp; /* in the caller */
1005 ainfo->offset = info->stack_size;
1006 info->stack_size += FREG_SIZE;
1009 ainfo->storage = ArgInFReg;
1010 ainfo->reg = info->fr;
1012 /* FP and GP slots do not overlap */
1018 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1019 /* First, see if we need to drop onto the stack */
1020 if (!info->on_stack) {
1021 if (info->gr > MIPS_LAST_ARG_REG)
1022 args_onto_stack (info);
1023 else if (info->fr > MIPS_LAST_FPARG_REG)
1024 args_onto_stack (info);
1027 /* Now, place the argument */
1028 if (info->on_stack) {
1029 g_assert(info->stack_size % 4 == 0);
1030 info->stack_size += (info->stack_size % 8);
1032 ainfo->storage = ArgOnStack;
1033 ainfo->reg = mips_sp; /* in the caller */
1034 ainfo->offset = info->stack_size;
1035 info->stack_size += FREG_SIZE;
1038 ainfo->storage = ArgInFReg;
1039 ainfo->reg = info->fr;
1041 /* FP and GP slots do not overlap */
1048 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
1051 int n = sig->hasthis + sig->param_count;
1053 MonoType* simpletype;
1055 gboolean is_pinvoke = sig->pinvoke;
1058 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1060 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1062 cinfo->fr = MIPS_FIRST_FPARG_REG;
1063 cinfo->gr = MIPS_FIRST_ARG_REG;
1064 cinfo->stack_size = 0;
1066 DEBUG(printf("calculate_sizes\n"));
1068 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1072 /* handle returning a struct */
1073 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1074 cinfo->struct_ret = cinfo->gr;
1075 add_int32_arg (cinfo, &cinfo->ret);
1079 add_int32_arg (cinfo, cinfo->args + n);
1084 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1085 * the first argument, allowing 'this' to be always passed in the first arg reg.
1086 * Also do this if the first argument is a reference type, since virtual calls
1087 * are sometimes made using calli without sig->hasthis set, like in the delegate
1090 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
1092 add_int32_arg (cinfo, cinfo->args + n);
1095 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1099 add_int32_arg (cinfo, &cinfo->ret);
1100 cinfo->struct_ret = cinfo->ret.reg;
1104 add_int32_arg (cinfo, cinfo->args + n);
1108 if (cinfo->vtype_retaddr) {
1109 add_int32_arg (cinfo, &cinfo->ret);
1110 cinfo->struct_ret = cinfo->ret.reg;
1115 DEBUG(printf("params: %d\n", sig->param_count));
1116 for (i = pstart; i < sig->param_count; ++i) {
1117 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1118 /* Prevent implicit arguments and sig_cookie from
1119 being passed in registers */
1120 args_onto_stack (cinfo);
1121 /* Emit the signature cookie just before the implicit arguments */
1122 add_int32_arg (cinfo, &cinfo->sig_cookie);
1124 DEBUG(printf("param %d: ", i));
1125 simpletype = mini_type_get_underlying_type (gsctx, sig->params [i]);
1126 switch (simpletype->type) {
1127 case MONO_TYPE_BOOLEAN:
1130 DEBUG(printf("1 byte\n"));
1131 cinfo->args [n].size = 1;
1132 add_int32_arg (cinfo, &cinfo->args[n]);
1135 case MONO_TYPE_CHAR:
1138 DEBUG(printf("2 bytes\n"));
1139 cinfo->args [n].size = 2;
1140 add_int32_arg (cinfo, &cinfo->args[n]);
1145 DEBUG(printf("4 bytes\n"));
1146 cinfo->args [n].size = 4;
1147 add_int32_arg (cinfo, &cinfo->args[n]);
1153 case MONO_TYPE_FNPTR:
1154 case MONO_TYPE_CLASS:
1155 case MONO_TYPE_OBJECT:
1156 case MONO_TYPE_STRING:
1157 case MONO_TYPE_SZARRAY:
1158 case MONO_TYPE_ARRAY:
1159 cinfo->args [n].size = sizeof (gpointer);
1160 add_int32_arg (cinfo, &cinfo->args[n]);
1163 case MONO_TYPE_GENERICINST:
1164 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1165 cinfo->args [n].size = sizeof (gpointer);
1166 add_int32_arg (cinfo, &cinfo->args[n]);
1171 case MONO_TYPE_TYPEDBYREF:
1172 case MONO_TYPE_VALUETYPE: {
1175 int has_offset = FALSE;
1177 gint size, alignment;
1180 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1181 size = sizeof (MonoTypedRef);
1182 alignment = sizeof (gpointer);
1184 klass = mono_class_from_mono_type (sig->params [i]);
1186 size = mono_class_native_size (klass, NULL);
1188 size = mono_class_value_size (klass, NULL);
1189 alignment = mono_class_min_align (klass);
1191 #if MIPS_PASS_STRUCTS_BY_VALUE
1192 /* Need to do alignment if struct contains long or double */
1193 if (alignment > 4) {
1194 /* Drop onto stack *before* looking at
1195 stack_size, if required. */
1196 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1197 args_onto_stack (cinfo);
1198 if (cinfo->stack_size & (alignment - 1)) {
1199 add_int32_arg (cinfo, &dummy_arg);
1201 g_assert (!(cinfo->stack_size & (alignment - 1)));
1205 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1206 mono_class_native_size (sig->params [i]->data.klass, NULL),
1207 cinfo->stack_size, alignment);
1209 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1210 g_assert (cinfo->args [n].size == 0);
1211 g_assert (cinfo->args [n].vtsize == 0);
1212 for (j = 0; j < nwords; ++j) {
1214 add_int32_arg (cinfo, &cinfo->args [n]);
1215 if (cinfo->on_stack)
1218 add_int32_arg (cinfo, &dummy_arg);
1219 if (!has_offset && cinfo->on_stack) {
1220 cinfo->args [n].offset = dummy_arg.offset;
1224 if (cinfo->on_stack)
1225 cinfo->args [n].vtsize += 1;
1227 cinfo->args [n].size += 1;
1229 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1230 cinfo->args [n].storage = ArgStructByVal;
1232 add_int32_arg (cinfo, &cinfo->args[n]);
1233 cinfo->args [n].storage = ArgStructByAddr;
1240 DEBUG(printf("8 bytes\n"));
1241 cinfo->args [n].size = 8;
1242 add_int64_arg (cinfo, &cinfo->args[n]);
1246 DEBUG(printf("R4\n"));
1247 cinfo->args [n].size = 4;
1248 add_float32_arg (cinfo, &cinfo->args[n]);
1252 DEBUG(printf("R8\n"));
1253 cinfo->args [n].size = 8;
1254 add_float64_arg (cinfo, &cinfo->args[n]);
1258 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1262 /* Handle the case where there are no implicit arguments */
1263 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1264 /* Prevent implicit arguments and sig_cookie from
1265 being passed in registers */
1266 args_onto_stack (cinfo);
1267 /* Emit the signature cookie just before the implicit arguments */
1268 add_int32_arg (cinfo, &cinfo->sig_cookie);
1272 simpletype = mini_type_get_underlying_type (gsctx, sig->ret);
1273 switch (simpletype->type) {
1274 case MONO_TYPE_BOOLEAN:
1279 case MONO_TYPE_CHAR:
1285 case MONO_TYPE_FNPTR:
1286 case MONO_TYPE_CLASS:
1287 case MONO_TYPE_OBJECT:
1288 case MONO_TYPE_SZARRAY:
1289 case MONO_TYPE_ARRAY:
1290 case MONO_TYPE_STRING:
1291 cinfo->ret.reg = mips_v0;
1295 cinfo->ret.reg = mips_v0;
1299 cinfo->ret.reg = mips_f0;
1300 cinfo->ret.storage = ArgInFReg;
1302 case MONO_TYPE_GENERICINST:
1303 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1304 cinfo->ret.reg = mips_v0;
1308 case MONO_TYPE_VALUETYPE:
1309 case MONO_TYPE_TYPEDBYREF:
1311 case MONO_TYPE_VOID:
1314 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1318 /* align stack size to 16 */
1319 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1321 cinfo->stack_usage = cinfo->stack_size;
1326 debug_omit_fp (void)
1329 return mono_debug_count ();
1336 * mono_arch_compute_omit_fp:
1338 * Determine whenever the frame pointer can be eliminated.
1341 mono_arch_compute_omit_fp (MonoCompile *cfg)
1343 MonoMethodSignature *sig;
1344 MonoMethodHeader *header;
1348 if (cfg->arch.omit_fp_computed)
1351 header = cfg->header;
1353 sig = mono_method_signature (cfg->method);
1355 if (!cfg->arch.cinfo)
1356 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1357 cinfo = cfg->arch.cinfo;
1360 * FIXME: Remove some of the restrictions.
1362 cfg->arch.omit_fp = TRUE;
1363 cfg->arch.omit_fp_computed = TRUE;
1365 if (cfg->disable_omit_fp)
1366 cfg->arch.omit_fp = FALSE;
1367 if (!debug_omit_fp ())
1368 cfg->arch.omit_fp = FALSE;
1369 if (cfg->method->save_lmf)
1370 cfg->arch.omit_fp = FALSE;
1371 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1372 cfg->arch.omit_fp = FALSE;
1373 if (header->num_clauses)
1374 cfg->arch.omit_fp = FALSE;
1375 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1376 cfg->arch.omit_fp = FALSE;
1377 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1378 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1379 cfg->arch.omit_fp = FALSE;
1381 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1382 * there are stack arguments.
1385 if (cinfo->stack_usage)
1386 cfg->arch.omit_fp = FALSE;
1390 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1391 MonoInst *ins = cfg->varinfo [i];
1394 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1397 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1401 * Set var information according to the calling convention. mips version.
1402 * The locals var stuff should most likely be split in another method.
1405 mono_arch_allocate_vars (MonoCompile *cfg)
1407 MonoMethodSignature *sig;
1408 MonoMethodHeader *header;
1410 int i, offset, size, align, curinst;
1411 int frame_reg = mips_sp;
1412 guint32 iregs_to_save = 0;
1414 guint32 fregs_to_restore;
1418 sig = mono_method_signature (cfg->method);
1420 if (!cfg->arch.cinfo)
1421 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1422 cinfo = cfg->arch.cinfo;
1424 mono_arch_compute_omit_fp (cfg);
1426 /* spill down, we'll fix it in a separate pass */
1427 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1429 /* allow room for the vararg method args: void* and long/double */
1430 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1431 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1433 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1434 * call convs needs to be handled this way.
1436 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1437 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1439 /* gtk-sharp and other broken code will dllimport vararg functions even with
1440 * non-varargs signatures. Since there is little hope people will get this right
1441 * we assume they won't.
1443 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1444 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1446 /* a0-a3 always present */
1447 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1449 header = cfg->header;
1451 if (cfg->arch.omit_fp)
1452 frame_reg = mips_sp;
1454 frame_reg = mips_fp;
1455 cfg->frame_reg = frame_reg;
1456 if (frame_reg != mips_sp) {
1457 cfg->used_int_regs |= 1 << frame_reg;
1462 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1463 /* FIXME: handle long and FP values */
1464 switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
1465 case MONO_TYPE_VOID:
1469 cfg->ret->opcode = OP_REGVAR;
1470 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1473 cfg->ret->opcode = OP_REGVAR;
1474 cfg->ret->inst_c0 = mips_v0;
1478 /* Space for outgoing parameters, including a0-a3 */
1479 offset += cfg->param_area;
1481 /* allow room to save the return value (if it's a struct) */
1482 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1485 /* Now handle the local variables */
1487 curinst = cfg->locals_start;
1488 for (i = curinst; i < cfg->num_varinfo; ++i) {
1489 inst = cfg->varinfo [i];
1490 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1493 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1494 * pinvoke wrappers when they call functions returning structure
1496 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1497 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1499 size = mono_type_size (inst->inst_vtype, &align);
1501 offset += align - 1;
1502 offset &= ~(align - 1);
1503 inst->inst_offset = offset;
1504 inst->opcode = OP_REGOFFSET;
1505 inst->inst_basereg = frame_reg;
1507 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1510 /* Space for LMF (if needed) */
1511 if (cfg->method->save_lmf) {
1512 /* align the offset to 16 bytes */
1513 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1514 cfg->arch.lmf_offset = offset;
1515 offset += sizeof (MonoLMF);
1518 if (sig->call_convention == MONO_CALL_VARARG) {
1522 /* Allocate a local slot to hold the sig cookie address */
1523 offset += align - 1;
1524 offset &= ~(align - 1);
1525 cfg->sig_cookie = offset;
1529 offset += SIZEOF_REGISTER - 1;
1530 offset &= ~(SIZEOF_REGISTER - 1);
1532 /* Space for saved registers */
1533 cfg->arch.iregs_offset = offset;
1534 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1535 if (iregs_to_save) {
1536 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1537 if (iregs_to_save & (1 << i)) {
1538 offset += SIZEOF_REGISTER;
1543 /* saved float registers */
1545 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1546 if (fregs_to_restore) {
1547 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1548 if (fregs_to_restore & (1 << i)) {
1549 offset += sizeof(double);
1555 #if _MIPS_SIM == _ABIO32
1556 /* Now add space for saving the ra */
1557 offset += SIZEOF_VOID_P;
1560 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1561 cfg->stack_offset = offset;
1562 cfg->arch.local_alloc_offset = cfg->stack_offset;
1566 * Now allocate stack slots for the int arg regs (a0 - a3)
1567 * On MIPS o32, these are just above the incoming stack pointer
1568 * Even if the arg has been assigned to a regvar, it gets a stack slot
1571 /* Return struct-by-value results in a hidden first argument */
1572 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1573 cfg->vret_addr->opcode = OP_REGOFFSET;
1574 cfg->vret_addr->inst_c0 = mips_a0;
1575 cfg->vret_addr->inst_offset = offset;
1576 cfg->vret_addr->inst_basereg = frame_reg;
1577 offset += SIZEOF_REGISTER;
1580 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1581 inst = cfg->args [i];
1582 if (inst->opcode != OP_REGVAR) {
1585 if (sig->hasthis && (i == 0))
1586 arg_type = &mono_defaults.object_class->byval_arg;
1588 arg_type = sig->params [i - sig->hasthis];
1590 inst->opcode = OP_REGOFFSET;
1591 size = mono_type_size (arg_type, &align);
1593 if (size < SIZEOF_REGISTER) {
1594 size = SIZEOF_REGISTER;
1595 align = SIZEOF_REGISTER;
1597 inst->inst_basereg = frame_reg;
1598 offset = (offset + align - 1) & ~(align - 1);
1599 inst->inst_offset = offset;
1601 if (cfg->verbose_level > 1)
1602 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1605 #if _MIPS_SIM == _ABIO32
1606 /* o32: Even a0-a3 get stack slots */
1607 size = SIZEOF_REGISTER;
1608 align = SIZEOF_REGISTER;
1609 inst->inst_basereg = frame_reg;
1610 offset = (offset + align - 1) & ~(align - 1);
1611 inst->inst_offset = offset;
1613 if (cfg->verbose_level > 1)
1614 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1618 #if _MIPS_SIM == _ABIN32
1619 /* Now add space for saving the ra */
1620 offset += SIZEOF_VOID_P;
1623 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1624 cfg->stack_offset = offset;
1625 cfg->arch.local_alloc_offset = cfg->stack_offset;
1630 mono_arch_create_vars (MonoCompile *cfg)
1632 MonoMethodSignature *sig;
1634 sig = mono_method_signature (cfg->method);
1636 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1637 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1638 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1639 printf ("vret_addr = ");
1640 mono_print_ins (cfg->vret_addr);
1645 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1646 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1650 * take the arguments and generate the arch-specific
1651 * instructions to properly call the function in call.
1652 * This includes pushing, moving arguments to the right register
1654 * Issue: who does the spilling if needed, and when?
1657 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1659 MonoMethodSignature *tmp_sig;
1662 if (call->tail_call)
1665 /* FIXME: Add support for signature tokens to AOT */
1666 cfg->disable_aot = TRUE;
1669 * mono_ArgIterator_Setup assumes the signature cookie is
1670 * passed first and all the arguments which were before it are
1671 * passed on the stack after the signature. So compensate by
1672 * passing a different signature.
1674 tmp_sig = mono_metadata_signature_dup (call->signature);
1675 tmp_sig->param_count -= call->signature->sentinelpos;
1676 tmp_sig->sentinelpos = 0;
1677 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1679 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1680 sig_arg->dreg = mono_alloc_ireg (cfg);
1681 sig_arg->inst_p0 = tmp_sig;
1682 MONO_ADD_INS (cfg->cbb, sig_arg);
1684 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1688 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1691 MonoMethodSignature *sig;
1696 sig = call->signature;
1697 n = sig->param_count + sig->hasthis;
1699 cinfo = get_call_info (NULL, cfg->mempool, sig);
1700 if (cinfo->struct_ret)
1701 call->used_iregs |= 1 << cinfo->struct_ret;
1703 for (i = 0; i < n; ++i) {
1704 ArgInfo *ainfo = cinfo->args + i;
1707 if (i >= sig->hasthis)
1708 t = sig->params [i - sig->hasthis];
1710 t = &mono_defaults.int_class->byval_arg;
1711 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1713 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1714 /* Emit the signature cookie just before the implicit arguments */
1715 emit_sig_cookie (cfg, call, cinfo);
1718 if (is_virtual && i == 0) {
1719 /* the argument will be attached to the call instrucion */
1720 in = call->args [i];
1721 call->used_iregs |= 1 << ainfo->reg;
1724 in = call->args [i];
1725 if (ainfo->storage == ArgInIReg) {
1726 #if SIZEOF_REGISTER == 4
1727 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1728 MONO_INST_NEW (cfg, ins, OP_MOVE);
1729 ins->dreg = mono_alloc_ireg (cfg);
1730 ins->sreg1 = in->dreg + 1;
1731 MONO_ADD_INS (cfg->cbb, ins);
1732 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1734 MONO_INST_NEW (cfg, ins, OP_MOVE);
1735 ins->dreg = mono_alloc_ireg (cfg);
1736 ins->sreg1 = in->dreg + 2;
1737 MONO_ADD_INS (cfg->cbb, ins);
1738 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1741 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1744 #if PROMOTE_R4_TO_R8
1745 /* ??? - convert to single first? */
1746 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1747 ins->dreg = mono_alloc_freg (cfg);
1748 ins->sreg1 = in->dreg;
1749 MONO_ADD_INS (cfg->cbb, ins);
1754 /* trying to load float value into int registers */
1755 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1756 ins->dreg = mono_alloc_ireg (cfg);
1758 MONO_ADD_INS (cfg->cbb, ins);
1759 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1760 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1761 /* trying to load float value into int registers */
1762 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1763 ins->dreg = mono_alloc_ireg (cfg);
1764 ins->sreg1 = in->dreg;
1765 MONO_ADD_INS (cfg->cbb, ins);
1766 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1768 MONO_INST_NEW (cfg, ins, OP_MOVE);
1769 ins->dreg = mono_alloc_ireg (cfg);
1770 ins->sreg1 = in->dreg;
1771 MONO_ADD_INS (cfg->cbb, ins);
1772 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1774 } else if (ainfo->storage == ArgStructByAddr) {
1775 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1776 ins->opcode = OP_OUTARG_VT;
1777 ins->sreg1 = in->dreg;
1778 ins->klass = in->klass;
1779 ins->inst_p0 = call;
1780 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1781 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1782 MONO_ADD_INS (cfg->cbb, ins);
1783 } else if (ainfo->storage == ArgStructByVal) {
1784 /* this is further handled in mono_arch_emit_outarg_vt () */
1785 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1786 ins->opcode = OP_OUTARG_VT;
1787 ins->sreg1 = in->dreg;
1788 ins->klass = in->klass;
1789 ins->inst_p0 = call;
1790 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1791 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1792 MONO_ADD_INS (cfg->cbb, ins);
1793 } else if (ainfo->storage == ArgOnStack) {
1794 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1795 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1796 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1797 if (t->type == MONO_TYPE_R8)
1798 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1800 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1802 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1804 } else if (ainfo->storage == ArgInFReg) {
1805 if (t->type == MONO_TYPE_VALUETYPE) {
1806 /* this is further handled in mono_arch_emit_outarg_vt () */
1807 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1808 ins->opcode = OP_OUTARG_VT;
1809 ins->sreg1 = in->dreg;
1810 ins->klass = in->klass;
1811 ins->inst_p0 = call;
1812 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1813 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1814 MONO_ADD_INS (cfg->cbb, ins);
1816 cfg->flags |= MONO_CFG_HAS_FPOUT;
1818 int dreg = mono_alloc_freg (cfg);
1820 if (ainfo->size == 4) {
1821 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1823 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1825 ins->sreg1 = in->dreg;
1826 MONO_ADD_INS (cfg->cbb, ins);
1829 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1830 cfg->flags |= MONO_CFG_HAS_FPOUT;
1833 g_assert_not_reached ();
1837 /* Handle the case where there are no implicit arguments */
1838 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1839 emit_sig_cookie (cfg, call, cinfo);
1841 if (cinfo->struct_ret) {
1844 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1845 vtarg->sreg1 = call->vret_var->dreg;
1846 vtarg->dreg = mono_alloc_preg (cfg);
1847 MONO_ADD_INS (cfg->cbb, vtarg);
1849 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1853 * Reverse the call->out_args list.
1856 MonoInst *prev = NULL, *list = call->out_args, *next;
1863 call->out_args = prev;
1866 call->stack_usage = cinfo->stack_usage;
1867 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1868 #if _MIPS_SIM == _ABIO32
1869 /* a0-a3 always present */
1870 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1872 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1873 cfg->flags |= MONO_CFG_HAS_CALLS;
1875 * should set more info in call, such as the stack space
1876 * used by the args that needs to be added back to esp
1881 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1883 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1884 ArgInfo *ainfo = ins->inst_p1;
1885 int ovf_size = ainfo->vtsize;
1886 int doffset = ainfo->offset;
1887 int i, soffset, dreg;
1889 if (ainfo->storage == ArgStructByVal) {
1891 if (cfg->verbose_level > 0) {
1892 char* nm = mono_method_full_name (cfg->method, TRUE);
1893 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1894 nm, doffset, ainfo->size, ovf_size);
1900 for (i = 0; i < ainfo->size; ++i) {
1901 dreg = mono_alloc_ireg (cfg);
1902 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1903 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1904 soffset += SIZEOF_REGISTER;
1906 if (ovf_size != 0) {
1907 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1909 } else if (ainfo->storage == ArgInFReg) {
1910 int tmpr = mono_alloc_freg (cfg);
1912 if (ainfo->size == 4)
1913 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1915 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1916 dreg = mono_alloc_freg (cfg);
1917 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1918 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1920 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1924 /* FIXME: alignment? */
1925 if (call->signature->pinvoke) {
1926 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1927 vtcopy->backend.is_pinvoke = 1;
1929 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1932 g_assert (ovf_size > 0);
1934 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1935 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1938 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1940 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1945 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1947 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1948 mono_method_signature (method)->ret);
1951 #if (SIZEOF_REGISTER == 4)
1952 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1955 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1956 ins->sreg1 = val->dreg + 1;
1957 ins->sreg2 = val->dreg + 2;
1958 MONO_ADD_INS (cfg->cbb, ins);
1962 if (ret->type == MONO_TYPE_R8) {
1963 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1966 if (ret->type == MONO_TYPE_R4) {
1967 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1971 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1975 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1977 MonoInst *ins, *n, *last_ins = NULL;
1979 if (cfg->verbose_level > 2)
1980 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1983 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1984 if (cfg->verbose_level > 2)
1985 mono_print_ins_index (0, ins);
1987 switch (ins->opcode) {
1989 case OP_LOAD_MEMBASE:
1990 case OP_LOADI4_MEMBASE:
1992 * OP_IADD reg2, reg1, const1
1993 * OP_LOAD_MEMBASE const2(reg2), reg3
1995 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1997 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)){
1998 int const1 = last_ins->inst_imm;
1999 int const2 = ins->inst_offset;
2001 if (mips_is_imm16 (const1 + const2)) {
2002 ins->inst_basereg = last_ins->sreg1;
2003 ins->inst_offset = const1 + const2;
2013 bb->last_ins = last_ins;
2017 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2019 MonoInst *ins, *n, *last_ins = NULL;
2022 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2023 MonoInst *last_ins = ins->prev;
2025 switch (ins->opcode) {
2027 /* remove unnecessary multiplication with 1 */
2028 if (ins->inst_imm == 1) {
2029 if (ins->dreg != ins->sreg1) {
2030 ins->opcode = OP_MOVE;
2032 MONO_DELETE_INS (bb, ins);
2036 int power2 = mono_is_power_of_two (ins->inst_imm);
2038 ins->opcode = OP_SHL_IMM;
2039 ins->inst_imm = power2;
2043 case OP_LOAD_MEMBASE:
2044 case OP_LOADI4_MEMBASE:
2046 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2047 * OP_LOAD_MEMBASE offset(basereg), reg
2049 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2050 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2051 ins->inst_basereg == last_ins->inst_destbasereg &&
2052 ins->inst_offset == last_ins->inst_offset) {
2053 if (ins->dreg == last_ins->sreg1) {
2054 MONO_DELETE_INS (bb, ins);
2057 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2058 ins->opcode = OP_MOVE;
2059 ins->sreg1 = last_ins->sreg1;
2064 * Note: reg1 must be different from the basereg in the second load
2065 * OP_LOAD_MEMBASE offset(basereg), reg1
2066 * OP_LOAD_MEMBASE offset(basereg), reg2
2068 * OP_LOAD_MEMBASE offset(basereg), reg1
2069 * OP_MOVE reg1, reg2
2071 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2072 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2073 ins->inst_basereg != last_ins->dreg &&
2074 ins->inst_basereg == last_ins->inst_basereg &&
2075 ins->inst_offset == last_ins->inst_offset) {
2077 if (ins->dreg == last_ins->dreg) {
2078 MONO_DELETE_INS (bb, ins);
2081 ins->opcode = OP_MOVE;
2082 ins->sreg1 = last_ins->dreg;
2085 //g_assert_not_reached ();
2090 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2091 * OP_LOAD_MEMBASE offset(basereg), reg
2093 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2094 * OP_ICONST reg, imm
2096 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2097 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2098 ins->inst_basereg == last_ins->inst_destbasereg &&
2099 ins->inst_offset == last_ins->inst_offset) {
2100 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2101 ins->opcode = OP_ICONST;
2102 ins->inst_c0 = last_ins->inst_imm;
2103 g_assert_not_reached (); // check this rule
2108 case OP_LOADU1_MEMBASE:
2109 case OP_LOADI1_MEMBASE:
2110 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2111 ins->inst_basereg == last_ins->inst_destbasereg &&
2112 ins->inst_offset == last_ins->inst_offset) {
2113 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2114 ins->sreg1 = last_ins->sreg1;
2117 case OP_LOADU2_MEMBASE:
2118 case OP_LOADI2_MEMBASE:
2119 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2120 ins->inst_basereg == last_ins->inst_destbasereg &&
2121 ins->inst_offset == last_ins->inst_offset) {
2122 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2123 ins->sreg1 = last_ins->sreg1;
2126 case OP_ICONV_TO_I4:
2127 case OP_ICONV_TO_U4:
2129 ins->opcode = OP_MOVE;
2133 if (ins->dreg == ins->sreg1) {
2134 MONO_DELETE_INS (bb, ins);
2138 * OP_MOVE sreg, dreg
2139 * OP_MOVE dreg, sreg
2141 if (last_ins && last_ins->opcode == OP_MOVE &&
2142 ins->sreg1 == last_ins->dreg &&
2143 ins->dreg == last_ins->sreg1) {
2144 MONO_DELETE_INS (bb, ins);
2152 bb->last_ins = last_ins;
2156 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2164 switch (ins->opcode) {
2167 case OP_LCOMPARE_IMM:
2168 mono_print_ins (ins);
2169 g_assert_not_reached ();
2172 tmp1 = mono_alloc_ireg (cfg);
2173 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2174 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2175 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2176 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2181 tmp1 = mono_alloc_ireg (cfg);
2182 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2183 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2184 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2185 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2190 tmp1 = mono_alloc_ireg (cfg);
2191 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2192 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2193 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2194 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2199 tmp1 = mono_alloc_ireg (cfg);
2200 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2201 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2202 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2203 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2215 mono_print_ins (ins);
2216 g_assert_not_reached ();
2219 tmp1 = mono_alloc_ireg (cfg);
2220 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2221 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2222 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2223 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2231 case OP_LCONV_TO_I1:
2232 case OP_LCONV_TO_I2:
2233 case OP_LCONV_TO_I4:
2234 case OP_LCONV_TO_I8:
2235 case OP_LCONV_TO_R4:
2236 case OP_LCONV_TO_R8:
2237 case OP_LCONV_TO_U4:
2238 case OP_LCONV_TO_U8:
2239 case OP_LCONV_TO_U2:
2240 case OP_LCONV_TO_U1:
2242 case OP_LCONV_TO_OVF_I:
2243 case OP_LCONV_TO_OVF_U:
2245 mono_print_ins (ins);
2246 g_assert_not_reached ();
2249 tmp1 = mono_alloc_ireg (cfg);
2250 tmp2 = mono_alloc_ireg (cfg);
2251 tmp3 = mono_alloc_ireg (cfg);
2252 tmp4 = mono_alloc_ireg (cfg);
2253 tmp5 = mono_alloc_ireg (cfg);
2255 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2257 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2258 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2260 /* add the high 32-bits, and add in the carry from the low 32-bits */
2261 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2262 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2264 /* Overflow happens if
2265 * neg + neg = pos or
2267 * XOR of the high bits returns 0 if the signs match
2268 * XOR of that with the high bit of the result return 1 if overflow.
2271 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2272 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2274 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2275 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2276 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2278 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2279 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2280 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2282 /* Now, if (tmp4 == 0) then overflow */
2283 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2287 case OP_LADD_OVF_UN:
2288 tmp1 = mono_alloc_ireg (cfg);
2289 tmp2 = mono_alloc_ireg (cfg);
2291 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2292 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2293 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2294 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2295 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2296 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2301 case OP_LMUL_OVF_UN:
2302 mono_print_ins (ins);
2303 g_assert_not_reached ();
2306 tmp1 = mono_alloc_ireg (cfg);
2307 tmp2 = mono_alloc_ireg (cfg);
2308 tmp3 = mono_alloc_ireg (cfg);
2309 tmp4 = mono_alloc_ireg (cfg);
2310 tmp5 = mono_alloc_ireg (cfg);
2312 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2314 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2315 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2316 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2318 /* Overflow happens if
2319 * neg - pos = pos or
2321 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2323 * tmp1 = (lhs ^ rhs)
2324 * tmp2 = (lhs ^ result)
2325 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2328 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2329 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2330 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2331 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2333 /* Now, if (tmp4 == 1) then overflow */
2334 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2338 case OP_LSUB_OVF_UN:
2339 tmp1 = mono_alloc_ireg (cfg);
2340 tmp2 = mono_alloc_ireg (cfg);
2342 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2343 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2344 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2345 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2347 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2348 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2352 case OP_LCONV_TO_OVF_I1_UN:
2353 case OP_LCONV_TO_OVF_I2_UN:
2354 case OP_LCONV_TO_OVF_I4_UN:
2355 case OP_LCONV_TO_OVF_I8_UN:
2356 case OP_LCONV_TO_OVF_U1_UN:
2357 case OP_LCONV_TO_OVF_U2_UN:
2358 case OP_LCONV_TO_OVF_U4_UN:
2359 case OP_LCONV_TO_OVF_U8_UN:
2360 case OP_LCONV_TO_OVF_I_UN:
2361 case OP_LCONV_TO_OVF_U_UN:
2362 case OP_LCONV_TO_OVF_I1:
2363 case OP_LCONV_TO_OVF_U1:
2364 case OP_LCONV_TO_OVF_I2:
2365 case OP_LCONV_TO_OVF_U2:
2366 case OP_LCONV_TO_OVF_I4:
2367 case OP_LCONV_TO_OVF_U4:
2368 case OP_LCONV_TO_OVF_I8:
2369 case OP_LCONV_TO_OVF_U8:
2377 case OP_LCONV_TO_R_UN:
2383 case OP_LSHR_UN_IMM:
2385 case OP_LDIV_UN_IMM:
2387 case OP_LREM_UN_IMM:
2398 mono_print_ins (ins);
2399 g_assert_not_reached ();
2401 case OP_LCONV_TO_R8_2:
2402 case OP_LCONV_TO_R4_2:
2403 case OP_LCONV_TO_R_UN_2:
2405 case OP_LCONV_TO_OVF_I4_2:
2406 tmp1 = mono_alloc_ireg (cfg);
2408 /* Overflows if reg2 != sign extension of reg1 */
2409 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2410 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2411 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2419 mono_print_ins (ins);
2420 g_assert_not_reached ();
2428 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2436 switch (ins->opcode) {
2438 tmp1 = mono_alloc_ireg (cfg);
2439 tmp2 = mono_alloc_ireg (cfg);
2440 tmp3 = mono_alloc_ireg (cfg);
2441 tmp4 = mono_alloc_ireg (cfg);
2442 tmp5 = mono_alloc_ireg (cfg);
2444 /* add the operands */
2446 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2448 /* Overflow happens if
2449 * neg + neg = pos or
2452 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2453 * XOR of the high bit returns 0 if the signs match
2454 * XOR of that with the high bit of the result return 1 if overflow.
2457 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2458 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2460 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2461 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2462 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2464 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2465 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2467 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2469 /* Now, if (tmp5 == 0) then overflow */
2470 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2471 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2472 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2476 case OP_IADD_OVF_UN:
2477 tmp1 = mono_alloc_ireg (cfg);
2479 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2480 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2481 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2482 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2483 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2488 tmp1 = mono_alloc_ireg (cfg);
2489 tmp2 = mono_alloc_ireg (cfg);
2490 tmp3 = mono_alloc_ireg (cfg);
2491 tmp4 = mono_alloc_ireg (cfg);
2492 tmp5 = mono_alloc_ireg (cfg);
2494 /* add the operands */
2496 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2498 /* Overflow happens if
2499 * neg - pos = pos or
2501 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2503 * tmp1 = (lhs ^ rhs)
2504 * tmp2 = (lhs ^ result)
2505 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2508 /* tmp3 = 1 if the signs of the two inputs differ */
2509 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2510 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2511 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2512 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2513 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2515 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2516 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2517 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2521 case OP_ISUB_OVF_UN:
2522 tmp1 = mono_alloc_ireg (cfg);
2524 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2525 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2526 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2527 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2528 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2535 map_to_reg_reg_op (int op)
2544 case OP_COMPARE_IMM:
2546 case OP_ICOMPARE_IMM:
2548 case OP_LCOMPARE_IMM:
2564 case OP_LOAD_MEMBASE:
2565 return OP_LOAD_MEMINDEX;
2566 case OP_LOADI4_MEMBASE:
2567 return OP_LOADI4_MEMINDEX;
2568 case OP_LOADU4_MEMBASE:
2569 return OP_LOADU4_MEMINDEX;
2570 case OP_LOADU1_MEMBASE:
2571 return OP_LOADU1_MEMINDEX;
2572 case OP_LOADI2_MEMBASE:
2573 return OP_LOADI2_MEMINDEX;
2574 case OP_LOADU2_MEMBASE:
2575 return OP_LOADU2_MEMINDEX;
2576 case OP_LOADI1_MEMBASE:
2577 return OP_LOADI1_MEMINDEX;
2578 case OP_LOADR4_MEMBASE:
2579 return OP_LOADR4_MEMINDEX;
2580 case OP_LOADR8_MEMBASE:
2581 return OP_LOADR8_MEMINDEX;
2582 case OP_STOREI1_MEMBASE_REG:
2583 return OP_STOREI1_MEMINDEX;
2584 case OP_STOREI2_MEMBASE_REG:
2585 return OP_STOREI2_MEMINDEX;
2586 case OP_STOREI4_MEMBASE_REG:
2587 return OP_STOREI4_MEMINDEX;
2588 case OP_STORE_MEMBASE_REG:
2589 return OP_STORE_MEMINDEX;
2590 case OP_STORER4_MEMBASE_REG:
2591 return OP_STORER4_MEMINDEX;
2592 case OP_STORER8_MEMBASE_REG:
2593 return OP_STORER8_MEMINDEX;
2594 case OP_STORE_MEMBASE_IMM:
2595 return OP_STORE_MEMBASE_REG;
2596 case OP_STOREI1_MEMBASE_IMM:
2597 return OP_STOREI1_MEMBASE_REG;
2598 case OP_STOREI2_MEMBASE_IMM:
2599 return OP_STOREI2_MEMBASE_REG;
2600 case OP_STOREI4_MEMBASE_IMM:
2601 return OP_STOREI4_MEMBASE_REG;
2602 case OP_STOREI8_MEMBASE_IMM:
2603 return OP_STOREI8_MEMBASE_REG;
2605 return mono_op_imm_to_op (op);
2609 map_to_mips_op (int op)
2613 return OP_MIPS_FBEQ;
2615 return OP_MIPS_FBGE;
2617 return OP_MIPS_FBGT;
2619 return OP_MIPS_FBLE;
2621 return OP_MIPS_FBLT;
2623 return OP_MIPS_FBNE;
2625 return OP_MIPS_FBGE_UN;
2627 return OP_MIPS_FBGT_UN;
2629 return OP_MIPS_FBLE_UN;
2631 return OP_MIPS_FBLT_UN;
2639 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2640 g_assert_not_reached ();
2644 #define NEW_INS(cfg,after,dest,op) do { \
2645 MONO_INST_NEW((cfg), (dest), (op)); \
2646 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2649 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2651 MONO_INST_NEW(cfg, temp, (op)); \
2652 mono_bblock_insert_after_ins (bb, (pos), temp); \
2653 temp->dreg = (_dreg); \
2654 temp->sreg1 = (_sreg1); \
2655 temp->sreg2 = (_sreg2); \
2659 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2661 MONO_INST_NEW(cfg, temp, (op)); \
2662 mono_bblock_insert_after_ins (bb, (pos), temp); \
2663 temp->dreg = (_dreg); \
2664 temp->sreg1 = (_sreg1); \
2665 temp->inst_c0 = (_imm); \
2670 * Remove from the instruction list the instructions that can't be
2671 * represented with very simple instructions with no register
2675 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2677 MonoInst *ins, *next, *temp, *last_ins = NULL;
2681 if (cfg->verbose_level > 2) {
2684 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2685 MONO_BB_FOR_EACH_INS (bb, ins) {
2686 mono_print_ins_index (idx++, ins);
2692 MONO_BB_FOR_EACH_INS (bb, ins) {
2694 switch (ins->opcode) {
2699 /* Branch opts can eliminate the branch */
2700 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2706 case OP_COMPARE_IMM:
2707 case OP_ICOMPARE_IMM:
2708 case OP_LCOMPARE_IMM:
2710 /* Branch opts can eliminate the branch */
2711 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2715 if (ins->inst_imm) {
2716 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2717 temp->inst_c0 = ins->inst_imm;
2718 temp->dreg = mono_alloc_ireg (cfg);
2719 ins->sreg2 = temp->dreg;
2723 ins->sreg2 = mips_zero;
2725 if (ins->opcode == OP_COMPARE_IMM)
2726 ins->opcode = OP_COMPARE;
2727 else if (ins->opcode == OP_ICOMPARE_IMM)
2728 ins->opcode = OP_ICOMPARE;
2729 else if (ins->opcode == OP_LCOMPARE_IMM)
2730 ins->opcode = OP_LCOMPARE;
2733 case OP_IDIV_UN_IMM:
2736 case OP_IREM_UN_IMM:
2737 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2738 temp->inst_c0 = ins->inst_imm;
2739 temp->dreg = mono_alloc_ireg (cfg);
2740 ins->sreg2 = temp->dreg;
2741 if (ins->opcode == OP_IDIV_IMM)
2742 ins->opcode = OP_IDIV;
2743 else if (ins->opcode == OP_IREM_IMM)
2744 ins->opcode = OP_IREM;
2745 else if (ins->opcode == OP_IDIV_UN_IMM)
2746 ins->opcode = OP_IDIV_UN;
2747 else if (ins->opcode == OP_IREM_UN_IMM)
2748 ins->opcode = OP_IREM_UN;
2750 /* handle rem separately */
2757 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2758 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2759 temp->inst_c0 = ins->inst_imm;
2760 temp->dreg = mono_alloc_ireg (cfg);
2761 ins->sreg2 = temp->dreg;
2762 ins->opcode = map_to_reg_reg_op (ins->opcode);
2772 /* unsigned 16 bit immediate */
2773 if (ins->inst_imm & 0xffff0000) {
2774 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2775 temp->inst_c0 = ins->inst_imm;
2776 temp->dreg = mono_alloc_ireg (cfg);
2777 ins->sreg2 = temp->dreg;
2778 ins->opcode = map_to_reg_reg_op (ins->opcode);
2785 /* signed 16 bit immediate */
2786 if (!mips_is_imm16 (ins->inst_imm)) {
2787 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2788 temp->inst_c0 = ins->inst_imm;
2789 temp->dreg = mono_alloc_ireg (cfg);
2790 ins->sreg2 = temp->dreg;
2791 ins->opcode = map_to_reg_reg_op (ins->opcode);
2797 if (!mips_is_imm16 (-ins->inst_imm)) {
2798 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2799 temp->inst_c0 = ins->inst_imm;
2800 temp->dreg = mono_alloc_ireg (cfg);
2801 ins->sreg2 = temp->dreg;
2802 ins->opcode = map_to_reg_reg_op (ins->opcode);
2808 if (ins->inst_imm == 1) {
2809 ins->opcode = OP_MOVE;
2812 if (ins->inst_imm == 0) {
2813 ins->opcode = OP_ICONST;
2817 imm = mono_is_power_of_two (ins->inst_imm);
2819 ins->opcode = OP_SHL_IMM;
2820 ins->inst_imm = imm;
2823 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2824 temp->inst_c0 = ins->inst_imm;
2825 temp->dreg = mono_alloc_ireg (cfg);
2826 ins->sreg2 = temp->dreg;
2827 ins->opcode = map_to_reg_reg_op (ins->opcode);
2830 case OP_LOCALLOC_IMM:
2831 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2832 temp->inst_c0 = ins->inst_imm;
2833 temp->dreg = mono_alloc_ireg (cfg);
2834 ins->sreg1 = temp->dreg;
2835 ins->opcode = OP_LOCALLOC;
2838 case OP_LOADR4_MEMBASE:
2839 case OP_STORER4_MEMBASE_REG:
2840 /* we can do two things: load the immed in a register
2841 * and use an indexed load, or see if the immed can be
2842 * represented as an ad_imm + a load with a smaller offset
2843 * that fits. We just do the first for now, optimize later.
2845 if (mips_is_imm16 (ins->inst_offset))
2847 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2848 temp->inst_c0 = ins->inst_offset;
2849 temp->dreg = mono_alloc_ireg (cfg);
2850 ins->sreg2 = temp->dreg;
2851 ins->opcode = map_to_reg_reg_op (ins->opcode);
2854 case OP_STORE_MEMBASE_IMM:
2855 case OP_STOREI1_MEMBASE_IMM:
2856 case OP_STOREI2_MEMBASE_IMM:
2857 case OP_STOREI4_MEMBASE_IMM:
2858 case OP_STOREI8_MEMBASE_IMM:
2859 if (!ins->inst_imm) {
2860 ins->sreg1 = mips_zero;
2861 ins->opcode = map_to_reg_reg_op (ins->opcode);
2864 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2865 temp->inst_c0 = ins->inst_imm;
2866 temp->dreg = mono_alloc_ireg (cfg);
2867 ins->sreg1 = temp->dreg;
2868 ins->opcode = map_to_reg_reg_op (ins->opcode);
2870 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2876 /* Branch opts can eliminate the branch */
2877 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2884 * remap compare/branch and compare/set
2885 * to MIPS specific opcodes.
2887 next->opcode = map_to_mips_op (next->opcode);
2888 next->sreg1 = ins->sreg1;
2889 next->sreg2 = ins->sreg2;
2896 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2897 temp->inst_c0 = (guint32)ins->inst_p0;
2898 temp->dreg = mono_alloc_ireg (cfg);
2899 ins->inst_basereg = temp->dreg;
2900 ins->inst_offset = 0;
2901 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2903 /* make it handle the possibly big ins->inst_offset
2904 * later optimize to use lis + load_membase
2909 g_assert (ins_is_compare(last_ins));
2910 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2911 NULLIFY_INS(last_ins);
2915 g_assert (ins_is_compare(last_ins));
2916 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2917 NULLIFY_INS(last_ins);
2921 g_assert (ins_is_compare(last_ins));
2922 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2923 last_ins->dreg = mono_alloc_ireg (cfg);
2924 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2928 g_assert (ins_is_compare(last_ins));
2929 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2930 last_ins->dreg = mono_alloc_ireg (cfg);
2931 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2935 g_assert (ins_is_compare(last_ins));
2936 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2937 last_ins->dreg = mono_alloc_ireg (cfg);
2938 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2942 g_assert (ins_is_compare(last_ins));
2943 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2944 last_ins->dreg = mono_alloc_ireg (cfg);
2945 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2949 g_assert (ins_is_compare(last_ins));
2950 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2951 last_ins->dreg = mono_alloc_ireg (cfg);
2952 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2956 g_assert (ins_is_compare(last_ins));
2957 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2958 last_ins->dreg = mono_alloc_ireg (cfg);
2959 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2963 g_assert (ins_is_compare(last_ins));
2964 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2965 last_ins->dreg = mono_alloc_ireg (cfg);
2966 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2970 g_assert (ins_is_compare(last_ins));
2971 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2972 last_ins->dreg = mono_alloc_ireg (cfg);
2973 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2978 g_assert (ins_is_compare(last_ins));
2979 last_ins->opcode = OP_IXOR;
2980 last_ins->dreg = mono_alloc_ireg(cfg);
2981 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2986 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2987 NULLIFY_INS(last_ins);
2993 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2994 NULLIFY_INS(last_ins);
2999 g_assert (ins_is_compare(last_ins));
3000 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
3001 MONO_DELETE_INS(bb, last_ins);
3006 g_assert (ins_is_compare(last_ins));
3007 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
3008 MONO_DELETE_INS(bb, last_ins);
3011 case OP_COND_EXC_EQ:
3012 case OP_COND_EXC_IEQ:
3013 g_assert (ins_is_compare(last_ins));
3014 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
3015 MONO_DELETE_INS(bb, last_ins);
3018 case OP_COND_EXC_GE:
3019 case OP_COND_EXC_IGE:
3020 g_assert (ins_is_compare(last_ins));
3021 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
3022 MONO_DELETE_INS(bb, last_ins);
3025 case OP_COND_EXC_GT:
3026 case OP_COND_EXC_IGT:
3027 g_assert (ins_is_compare(last_ins));
3028 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
3029 MONO_DELETE_INS(bb, last_ins);
3032 case OP_COND_EXC_LE:
3033 case OP_COND_EXC_ILE:
3034 g_assert (ins_is_compare(last_ins));
3035 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
3036 MONO_DELETE_INS(bb, last_ins);
3039 case OP_COND_EXC_LT:
3040 case OP_COND_EXC_ILT:
3041 g_assert (ins_is_compare(last_ins));
3042 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
3043 MONO_DELETE_INS(bb, last_ins);
3046 case OP_COND_EXC_NE_UN:
3047 case OP_COND_EXC_INE_UN:
3048 g_assert (ins_is_compare(last_ins));
3049 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
3050 MONO_DELETE_INS(bb, last_ins);
3053 case OP_COND_EXC_GE_UN:
3054 case OP_COND_EXC_IGE_UN:
3055 g_assert (ins_is_compare(last_ins));
3056 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
3057 MONO_DELETE_INS(bb, last_ins);
3060 case OP_COND_EXC_GT_UN:
3061 case OP_COND_EXC_IGT_UN:
3062 g_assert (ins_is_compare(last_ins));
3063 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
3064 MONO_DELETE_INS(bb, last_ins);
3067 case OP_COND_EXC_LE_UN:
3068 case OP_COND_EXC_ILE_UN:
3069 g_assert (ins_is_compare(last_ins));
3070 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
3071 MONO_DELETE_INS(bb, last_ins);
3074 case OP_COND_EXC_LT_UN:
3075 case OP_COND_EXC_ILT_UN:
3076 g_assert (ins_is_compare(last_ins));
3077 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
3078 MONO_DELETE_INS(bb, last_ins);
3081 case OP_COND_EXC_OV:
3082 case OP_COND_EXC_IOV: {
3083 int tmp1, tmp2, tmp3, tmp4, tmp5;
3084 MonoInst *pos = last_ins;
3086 /* Overflow happens if
3087 * neg + neg = pos or
3090 * (bit31s of operands match) AND (bit31 of operand
3091 * != bit31 of result)
3092 * XOR of the high bit returns 0 if the signs match
3093 * XOR of that with the high bit of the result return 1
3096 g_assert (last_ins->opcode == OP_IADC);
3098 tmp1 = mono_alloc_ireg (cfg);
3099 tmp2 = mono_alloc_ireg (cfg);
3100 tmp3 = mono_alloc_ireg (cfg);
3101 tmp4 = mono_alloc_ireg (cfg);
3102 tmp5 = mono_alloc_ireg (cfg);
3104 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3105 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
3107 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3108 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
3109 INS (pos, OP_INOT, tmp3, tmp2, -1);
3111 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3112 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
3113 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3115 /* Now, if (tmp5 == 0) then overflow */
3116 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3121 case OP_COND_EXC_NO:
3122 case OP_COND_EXC_INO:
3123 g_assert_not_reached ();
3127 case OP_COND_EXC_IC:
3128 g_assert_not_reached ();
3131 case OP_COND_EXC_NC:
3132 case OP_COND_EXC_INC:
3133 g_assert_not_reached ();
3139 bb->last_ins = last_ins;
3140 bb->max_vreg = cfg->next_vreg;
3143 if (cfg->verbose_level > 2) {
3146 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3147 MONO_BB_FOR_EACH_INS (bb, ins) {
3148 mono_print_ins_index (idx++, ins);
3157 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3159 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3161 mips_truncwd (code, mips_ftemp, sreg);
3163 mips_cvtwd (code, mips_ftemp, sreg);
3165 mips_mfc1 (code, dreg, mips_ftemp);
3168 mips_andi (code, dreg, dreg, 0xff);
3169 else if (size == 2) {
3170 mips_sll (code, dreg, dreg, 16);
3171 mips_srl (code, dreg, dreg, 16);
3175 mips_sll (code, dreg, dreg, 24);
3176 mips_sra (code, dreg, dreg, 24);
3178 else if (size == 2) {
3179 mips_sll (code, dreg, dreg, 16);
3180 mips_sra (code, dreg, dreg, 16);
3187 * emit_load_volatile_arguments:
3189 * Load volatile arguments from the stack to the original input registers.
3190 * Required before a tail call.
3193 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3195 MonoMethod *method = cfg->method;
3196 MonoMethodSignature *sig;
3201 sig = mono_method_signature (method);
3203 if (!cfg->arch.cinfo)
3204 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
3205 cinfo = cfg->arch.cinfo;
3207 if (cinfo->struct_ret) {
3208 ArgInfo *ainfo = &cinfo->ret;
3209 inst = cfg->vret_addr;
3210 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3213 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3214 ArgInfo *ainfo = cinfo->args + i;
3215 inst = cfg->args [i];
3216 if (inst->opcode == OP_REGVAR) {
3217 if (ainfo->storage == ArgInIReg)
3218 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3219 else if (ainfo->storage == ArgInFReg)
3220 g_assert_not_reached();
3221 else if (ainfo->storage == ArgOnStack) {
3224 g_assert_not_reached ();
3226 if (ainfo->storage == ArgInIReg) {
3227 g_assert (mips_is_imm16 (inst->inst_offset));
3228 switch (ainfo->size) {
3230 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3233 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3237 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3240 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3241 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3244 g_assert_not_reached ();
3247 } else if (ainfo->storage == ArgOnStack) {
3249 } else if (ainfo->storage == ArgInFReg) {
3250 g_assert (mips_is_imm16 (inst->inst_offset));
3251 if (ainfo->size == 8) {
3252 #if _MIPS_SIM == _ABIO32
3253 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3254 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3255 #elif _MIPS_SIM == _ABIN32
3256 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3259 else if (ainfo->size == 4)
3260 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3262 g_assert_not_reached ();
3263 } else if (ainfo->storage == ArgStructByVal) {
3265 int doffset = inst->inst_offset;
3267 g_assert (mips_is_imm16 (inst->inst_offset));
3268 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3269 for (i = 0; i < ainfo->size; ++i) {
3270 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3271 doffset += SIZEOF_REGISTER;
3273 } else if (ainfo->storage == ArgStructByAddr) {
3274 g_assert (mips_is_imm16 (inst->inst_offset));
3275 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3277 g_assert_not_reached ();
3285 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3287 int size = cfg->param_area;
3289 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3290 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3295 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3296 if (ppc_is_imm16 (-size)) {
3297 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3299 ppc_load (code, ppc_r11, -size);
3300 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3307 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3309 int size = cfg->param_area;
3311 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3312 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3317 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3318 if (ppc_is_imm16 (size)) {
3319 ppc_stwu (code, ppc_r0, size, ppc_sp);
3321 ppc_load (code, ppc_r11, size);
3322 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3329 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3334 guint8 *code = cfg->native_code + cfg->code_len;
3335 MonoInst *last_ins = NULL;
3336 guint last_offset = 0;
3340 /* we don't align basic blocks of loops on mips */
3342 if (cfg->verbose_level > 2)
3343 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3345 cpos = bb->max_offset;
3348 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3349 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3350 g_assert (!mono_compile_aot);
3353 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3354 /* this is not thread save, but good enough */
3355 /* fixme: howto handle overflows? */
3356 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3357 mips_lw (code, mips_temp, mips_at, 0);
3358 mips_addiu (code, mips_temp, mips_temp, 1);
3359 mips_sw (code, mips_temp, mips_at, 0);
3362 MONO_BB_FOR_EACH_INS (bb, ins) {
3363 offset = code - cfg->native_code;
3365 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3367 if (offset > (cfg->code_size - max_len - 16)) {
3368 cfg->code_size *= 2;
3369 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3370 code = cfg->native_code + offset;
3372 mono_debug_record_line_number (cfg, ins, offset);
3373 if (cfg->verbose_level > 2) {
3374 g_print (" @ 0x%x\t", offset);
3375 mono_print_ins_index (ins_cnt++, ins);
3377 /* Check for virtual regs that snuck by */
3378 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3380 switch (ins->opcode) {
3381 case OP_RELAXED_NOP:
3384 case OP_DUMMY_STORE:
3385 case OP_NOT_REACHED:
3388 case OP_SEQ_POINT: {
3389 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3390 guint32 addr = (guint32)ss_trigger_page;
3392 mips_load_const (code, mips_t9, addr);
3393 mips_lw (code, mips_t9, mips_t9, 0);
3396 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3399 * A placeholder for a possible breakpoint inserted by
3400 * mono_arch_set_breakpoint ().
3402 /* mips_load_const () + mips_lw */
3409 g_assert_not_reached();
3411 emit_tls_access (code, ins->dreg, ins->inst_offset);
3415 mips_mult (code, ins->sreg1, ins->sreg2);
3416 mips_mflo (code, ins->dreg);
3417 mips_mfhi (code, ins->dreg+1);
3420 mips_multu (code, ins->sreg1, ins->sreg2);
3421 mips_mflo (code, ins->dreg);
3422 mips_mfhi (code, ins->dreg+1);
3424 case OP_MEMORY_BARRIER:
3429 case OP_STOREI1_MEMBASE_IMM:
3430 mips_load_const (code, mips_temp, ins->inst_imm);
3431 if (mips_is_imm16 (ins->inst_offset)) {
3432 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3434 mips_load_const (code, mips_at, ins->inst_offset);
3435 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3438 case OP_STOREI2_MEMBASE_IMM:
3439 mips_load_const (code, mips_temp, ins->inst_imm);
3440 if (mips_is_imm16 (ins->inst_offset)) {
3441 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3443 mips_load_const (code, mips_at, ins->inst_offset);
3444 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3447 case OP_STOREI8_MEMBASE_IMM:
3448 mips_load_const (code, mips_temp, ins->inst_imm);
3449 if (mips_is_imm16 (ins->inst_offset)) {
3450 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3452 mips_load_const (code, mips_at, ins->inst_offset);
3453 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3456 case OP_STORE_MEMBASE_IMM:
3457 case OP_STOREI4_MEMBASE_IMM:
3458 mips_load_const (code, mips_temp, ins->inst_imm);
3459 if (mips_is_imm16 (ins->inst_offset)) {
3460 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3462 mips_load_const (code, mips_at, ins->inst_offset);
3463 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3466 case OP_STOREI1_MEMBASE_REG:
3467 if (mips_is_imm16 (ins->inst_offset)) {
3468 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3470 mips_load_const (code, mips_at, ins->inst_offset);
3471 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3472 mips_sb (code, ins->sreg1, mips_at, 0);
3475 case OP_STOREI2_MEMBASE_REG:
3476 if (mips_is_imm16 (ins->inst_offset)) {
3477 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3479 mips_load_const (code, mips_at, ins->inst_offset);
3480 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3481 mips_sh (code, ins->sreg1, mips_at, 0);
3484 case OP_STORE_MEMBASE_REG:
3485 case OP_STOREI4_MEMBASE_REG:
3486 if (mips_is_imm16 (ins->inst_offset)) {
3487 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3489 mips_load_const (code, mips_at, ins->inst_offset);
3490 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3491 mips_sw (code, ins->sreg1, mips_at, 0);
3494 case OP_STOREI8_MEMBASE_REG:
3495 if (mips_is_imm16 (ins->inst_offset)) {
3496 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3498 mips_load_const (code, mips_at, ins->inst_offset);
3499 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3500 mips_sd (code, ins->sreg1, mips_at, 0);
3504 g_assert_not_reached ();
3505 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3506 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3508 case OP_LOADI8_MEMBASE:
3509 if (mips_is_imm16 (ins->inst_offset)) {
3510 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3512 mips_load_const (code, mips_at, ins->inst_offset);
3513 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3514 mips_ld (code, ins->dreg, mips_at, 0);
3517 case OP_LOAD_MEMBASE:
3518 case OP_LOADI4_MEMBASE:
3519 case OP_LOADU4_MEMBASE:
3520 g_assert (ins->dreg != -1);
3521 if (mips_is_imm16 (ins->inst_offset)) {
3522 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3524 mips_load_const (code, mips_at, ins->inst_offset);
3525 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3526 mips_lw (code, ins->dreg, mips_at, 0);
3529 case OP_LOADI1_MEMBASE:
3530 if (mips_is_imm16 (ins->inst_offset)) {
3531 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3533 mips_load_const (code, mips_at, ins->inst_offset);
3534 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3535 mips_lb (code, ins->dreg, mips_at, 0);
3538 case OP_LOADU1_MEMBASE:
3539 if (mips_is_imm16 (ins->inst_offset)) {
3540 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3542 mips_load_const (code, mips_at, ins->inst_offset);
3543 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3544 mips_lbu (code, ins->dreg, mips_at, 0);
3547 case OP_LOADI2_MEMBASE:
3548 if (mips_is_imm16 (ins->inst_offset)) {
3549 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3551 mips_load_const (code, mips_at, ins->inst_offset);
3552 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3553 mips_lh (code, ins->dreg, mips_at, 0);
3556 case OP_LOADU2_MEMBASE:
3557 if (mips_is_imm16 (ins->inst_offset)) {
3558 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3560 mips_load_const (code, mips_at, ins->inst_offset);
3561 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3562 mips_lhu (code, ins->dreg, mips_at, 0);
3565 case OP_ICONV_TO_I1:
3566 mips_sll (code, mips_at, ins->sreg1, 24);
3567 mips_sra (code, ins->dreg, mips_at, 24);
3569 case OP_ICONV_TO_I2:
3570 mips_sll (code, mips_at, ins->sreg1, 16);
3571 mips_sra (code, ins->dreg, mips_at, 16);
3573 case OP_ICONV_TO_U1:
3574 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3576 case OP_ICONV_TO_U2:
3577 mips_sll (code, mips_at, ins->sreg1, 16);
3578 mips_srl (code, ins->dreg, mips_at, 16);
3581 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3584 g_assert (mips_is_imm16 (ins->inst_imm));
3585 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3588 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3591 g_assert (mips_is_imm16 (ins->inst_imm));
3592 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3596 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3597 * So instead of emitting a trap, we emit a call a C function and place a
3600 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3601 (gpointer)"mono_break");
3602 mips_load (code, mips_t9, 0x1f1f1f1f);
3603 mips_jalr (code, mips_t9, mips_ra);
3607 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3610 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3615 g_assert (mips_is_imm16 (ins->inst_imm));
3616 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3619 g_assert (mips_is_imm16 (ins->inst_imm));
3620 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3624 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3627 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3632 // we add the negated value
3633 g_assert (mips_is_imm16 (-ins->inst_imm));
3634 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3638 // we add the negated value
3639 g_assert (mips_is_imm16 (-ins->inst_imm));
3640 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3645 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3651 g_assert (!(ins->inst_imm & 0xffff0000));
3652 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3657 guint32 *divisor_is_m1;
3658 guint32 *dividend_is_minvalue;
3659 guint32 *divisor_is_zero;
3661 mips_load_const (code, mips_at, -1);
3662 divisor_is_m1 = (guint32 *)(void *)code;
3663 mips_bne (code, ins->sreg2, mips_at, 0);
3664 mips_lui (code, mips_at, mips_zero, 0x8000);
3665 dividend_is_minvalue = (guint32 *)(void *)code;
3666 mips_bne (code, ins->sreg1, mips_at, 0);
3669 /* Divide Int32.MinValue by -1 -- throw exception */
3670 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3672 mips_patch (divisor_is_m1, (guint32)code);
3673 mips_patch (dividend_is_minvalue, (guint32)code);
3675 /* Put divide in branch delay slot (NOT YET) */
3676 divisor_is_zero = (guint32 *)(void *)code;
3677 mips_bne (code, ins->sreg2, mips_zero, 0);
3680 /* Divide by zero -- throw exception */
3681 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3683 mips_patch (divisor_is_zero, (guint32)code);
3684 mips_div (code, ins->sreg1, ins->sreg2);
3685 if (ins->opcode == OP_IDIV)
3686 mips_mflo (code, ins->dreg);
3688 mips_mfhi (code, ins->dreg);
3693 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3695 /* Put divide in branch delay slot (NOT YET) */
3696 mips_bne (code, ins->sreg2, mips_zero, 0);
3699 /* Divide by zero -- throw exception */
3700 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3702 mips_patch (divisor_is_zero, (guint32)code);
3703 mips_divu (code, ins->sreg1, ins->sreg2);
3704 if (ins->opcode == OP_IDIV_UN)
3705 mips_mflo (code, ins->dreg);
3707 mips_mfhi (code, ins->dreg);
3711 g_assert_not_reached ();
3713 ppc_load (code, ppc_r11, ins->inst_imm);
3714 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3715 ppc_mfspr (code, ppc_r0, ppc_xer);
3716 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3717 /* FIXME: use OverflowException for 0x80000000/-1 */
3718 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3720 g_assert_not_reached();
3723 g_assert_not_reached ();
3725 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3729 g_assert (!(ins->inst_imm & 0xffff0000));
3730 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3733 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3737 /* unsigned 16-bit immediate */
3738 g_assert (!(ins->inst_imm & 0xffff0000));
3739 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3742 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3746 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3749 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3752 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3756 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3759 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3762 case OP_ISHR_UN_IMM:
3763 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3765 case OP_LSHR_UN_IMM:
3766 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3769 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3772 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3776 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3779 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3782 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3786 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3788 mips_mult (code, ins->sreg1, ins->sreg2);
3789 mips_mflo (code, ins->dreg);
3794 #if SIZEOF_REGISTER == 8
3796 mips_dmult (code, ins->sreg1, ins->sreg2);
3797 mips_mflo (code, ins->dreg);
3802 mips_mult (code, ins->sreg1, ins->sreg2);
3803 mips_mflo (code, ins->dreg);
3804 mips_mfhi (code, mips_at);
3807 mips_sra (code, mips_temp, ins->dreg, 31);
3808 patch = (guint32 *)(void *)code;
3809 mips_beq (code, mips_temp, mips_at, 0);
3811 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3812 mips_patch (patch, (guint32)code);
3815 case OP_IMUL_OVF_UN: {
3817 mips_mult (code, ins->sreg1, ins->sreg2);
3818 mips_mflo (code, ins->dreg);
3819 mips_mfhi (code, mips_at);
3822 patch = (guint32 *)(void *)code;
3823 mips_beq (code, mips_at, mips_zero, 0);
3825 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3826 mips_patch (patch, (guint32)code);
3830 mips_load_const (code, ins->dreg, ins->inst_c0);
3832 #if SIZEOF_REGISTER == 8
3834 mips_load_const (code, ins->dreg, ins->inst_c0);
3838 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3839 mips_load (code, ins->dreg, 0);
3843 mips_mtc1 (code, ins->dreg, ins->sreg1);
3845 case OP_MIPS_MTC1S_2:
3846 mips_mtc1 (code, ins->dreg, ins->sreg1);
3847 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3850 mips_mfc1 (code, ins->dreg, ins->sreg1);
3853 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3857 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3859 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3860 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3864 case OP_ICONV_TO_I4:
3865 case OP_ICONV_TO_U4:
3867 if (ins->dreg != ins->sreg1)
3868 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3870 #if SIZEOF_REGISTER == 8
3872 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3873 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3876 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3877 mips_dsra (code, ins->dreg, ins->dreg, 32);
3881 int lsreg = mips_v0 + ls_word_idx;
3882 int msreg = mips_v0 + ms_word_idx;
3884 /* Get sreg1 into lsreg, sreg2 into msreg */
3886 if (ins->sreg1 == msreg) {
3887 if (ins->sreg1 != mips_at)
3888 MIPS_MOVE (code, mips_at, ins->sreg1);
3889 if (ins->sreg2 != msreg)
3890 MIPS_MOVE (code, msreg, ins->sreg2);
3891 MIPS_MOVE (code, lsreg, mips_at);
3894 if (ins->sreg2 != msreg)
3895 MIPS_MOVE (code, msreg, ins->sreg2);
3896 if (ins->sreg1 != lsreg)
3897 MIPS_MOVE (code, lsreg, ins->sreg1);
3902 if (ins->dreg != ins->sreg1) {
3903 mips_fmovd (code, ins->dreg, ins->sreg1);
3907 /* Convert from double to float and leave it there */
3908 mips_cvtsd (code, ins->dreg, ins->sreg1);
3910 case OP_FCONV_TO_R4:
3912 mips_cvtsd (code, ins->dreg, ins->sreg1);
3914 /* Just a move, no precision change */
3915 if (ins->dreg != ins->sreg1) {
3916 mips_fmovd (code, ins->dreg, ins->sreg1);
3921 code = emit_load_volatile_arguments(cfg, code);
3924 * Pop our stack, then jump to specified method (tail-call)
3925 * Keep in sync with mono_arch_emit_epilog
3927 code = mono_arch_emit_epilog_sub (cfg, code);
3929 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3930 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3931 mips_load (code, mips_t9, 0);
3932 mips_jr (code, mips_t9);
3936 /* ensure ins->sreg1 is not NULL */
3937 mips_lw (code, mips_zero, ins->sreg1, 0);
3940 g_assert (mips_is_imm16 (cfg->sig_cookie));
3941 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3942 mips_sw (code, mips_at, ins->sreg1, 0);
3955 case OP_VOIDCALL_REG:
3957 case OP_FCALL_MEMBASE:
3958 case OP_LCALL_MEMBASE:
3959 case OP_VCALL_MEMBASE:
3960 case OP_VCALL2_MEMBASE:
3961 case OP_VOIDCALL_MEMBASE:
3962 case OP_CALL_MEMBASE:
3963 call = (MonoCallInst*)ins;
3964 switch (ins->opcode) {
3971 if (ins->flags & MONO_INST_HAS_METHOD) {
3972 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3973 mips_load (code, mips_t9, call->method);
3976 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3977 mips_load (code, mips_t9, call->fptr);
3979 mips_jalr (code, mips_t9, mips_ra);
3986 case OP_VOIDCALL_REG:
3988 MIPS_MOVE (code, mips_t9, ins->sreg1);
3989 mips_jalr (code, mips_t9, mips_ra);
3992 case OP_FCALL_MEMBASE:
3993 case OP_LCALL_MEMBASE:
3994 case OP_VCALL_MEMBASE:
3995 case OP_VCALL2_MEMBASE:
3996 case OP_VOIDCALL_MEMBASE:
3997 case OP_CALL_MEMBASE:
3998 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3999 mips_jalr (code, mips_t9, mips_ra);
4003 #if PROMOTE_R4_TO_R8
4004 /* returned an FP R4 (single), promote to R8 (double) in place */
4005 switch (ins->opcode) {
4008 case OP_FCALL_MEMBASE:
4009 if (call->signature->ret->type == MONO_TYPE_R4)
4010 mips_cvtds (code, mips_f0, mips_f0);
4018 int area_offset = cfg->param_area;
4020 /* Round up ins->sreg1, mips_at ends up holding size */
4021 mips_addiu (code, mips_at, ins->sreg1, 31);
4022 mips_addiu (code, mips_temp, mips_zero, ~31);
4023 mips_and (code, mips_at, mips_at, mips_temp);
4025 mips_subu (code, mips_sp, mips_sp, mips_at);
4026 g_assert (mips_is_imm16 (area_offset));
4027 mips_addiu (code, ins->dreg, mips_sp, area_offset);
4029 if (ins->flags & MONO_INST_INIT) {
4032 buf = (guint32*)(void*)code;
4033 mips_beq (code, mips_at, mips_zero, 0);
4036 mips_move (code, mips_temp, ins->dreg);
4037 mips_sb (code, mips_zero, mips_temp, 0);
4038 mips_addiu (code, mips_at, mips_at, -1);
4039 mips_bne (code, mips_at, mips_zero, -3);
4040 mips_addiu (code, mips_temp, mips_temp, 1);
4042 mips_patch (buf, (guint32)code);
4047 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
4048 mips_move (code, mips_a0, ins->sreg1);
4049 mips_call (code, mips_t9, addr);
4050 mips_break (code, 0xfc);
4054 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
4055 mips_move (code, mips_a0, ins->sreg1);
4056 mips_call (code, mips_t9, addr);
4057 mips_break (code, 0xfb);
4060 case OP_START_HANDLER: {
4062 * The START_HANDLER instruction marks the beginning of
4063 * a handler block. It is called using a call
4064 * instruction, so mips_ra contains the return address.
4065 * Since the handler executes in the same stack frame
4066 * as the method itself, we can't use save/restore to
4067 * save the return address. Instead, we save it into
4068 * a dedicated variable.
4070 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4071 g_assert (spvar->inst_basereg != mips_sp);
4072 code = emit_reserve_param_area (cfg, code);
4074 if (mips_is_imm16 (spvar->inst_offset)) {
4075 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4077 mips_load_const (code, mips_at, spvar->inst_offset);
4078 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4079 mips_sw (code, mips_ra, mips_at, 0);
4083 case OP_ENDFILTER: {
4084 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4085 g_assert (spvar->inst_basereg != mips_sp);
4086 code = emit_unreserve_param_area (cfg, code);
4088 if (ins->sreg1 != mips_v0)
4089 MIPS_MOVE (code, mips_v0, ins->sreg1);
4090 if (mips_is_imm16 (spvar->inst_offset)) {
4091 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4093 mips_load_const (code, mips_at, spvar->inst_offset);
4094 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4095 mips_lw (code, mips_ra, mips_at, 0);
4097 mips_jr (code, mips_ra);
4101 case OP_ENDFINALLY: {
4102 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4103 g_assert (spvar->inst_basereg != mips_sp);
4104 code = emit_unreserve_param_area (cfg, code);
4105 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
4106 mips_jalr (code, mips_t9, mips_ra);
4110 case OP_CALL_HANDLER:
4111 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4112 mips_lui (code, mips_t9, mips_zero, 0);
4113 mips_addiu (code, mips_t9, mips_t9, 0);
4114 mips_jalr (code, mips_t9, mips_ra);
4116 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4117 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4120 ins->inst_c0 = code - cfg->native_code;
4123 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4124 if (cfg->arch.long_branch) {
4125 mips_lui (code, mips_at, mips_zero, 0);
4126 mips_addiu (code, mips_at, mips_at, 0);
4127 mips_jr (code, mips_at);
4131 mips_beq (code, mips_zero, mips_zero, 0);
4136 mips_jr (code, ins->sreg1);
4142 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4143 if (offset > (cfg->code_size - max_len - 16)) {
4144 cfg->code_size += max_len;
4145 cfg->code_size *= 2;
4146 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4147 code = cfg->native_code + offset;
4149 g_assert (ins->sreg1 != -1);
4150 mips_sll (code, mips_at, ins->sreg1, 2);
4151 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4152 MIPS_MOVE (code, mips_t8, mips_ra);
4153 mips_bgezal (code, mips_zero, 1); /* bal */
4155 mips_addu (code, mips_t9, mips_ra, mips_at);
4156 /* Table is 16 or 20 bytes from target of bal above */
4157 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4158 MIPS_MOVE (code, mips_ra, mips_t8);
4159 mips_lw (code, mips_t9, mips_t9, 20);
4162 mips_lw (code, mips_t9, mips_t9, 16);
4163 mips_jalr (code, mips_t9, mips_t8);
4165 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4166 mips_emit32 (code, 0xfefefefe);
4171 mips_addiu (code, ins->dreg, mips_zero, 1);
4172 mips_beq (code, mips_at, mips_zero, 2);
4174 MIPS_MOVE (code, ins->dreg, mips_zero);
4180 mips_addiu (code, ins->dreg, mips_zero, 1);
4181 mips_bltz (code, mips_at, 2);
4183 MIPS_MOVE (code, ins->dreg, mips_zero);
4189 mips_addiu (code, ins->dreg, mips_zero, 1);
4190 mips_bgtz (code, mips_at, 2);
4192 MIPS_MOVE (code, ins->dreg, mips_zero);
4195 case OP_MIPS_COND_EXC_EQ:
4196 case OP_MIPS_COND_EXC_GE:
4197 case OP_MIPS_COND_EXC_GT:
4198 case OP_MIPS_COND_EXC_LE:
4199 case OP_MIPS_COND_EXC_LT:
4200 case OP_MIPS_COND_EXC_NE_UN:
4201 case OP_MIPS_COND_EXC_GE_UN:
4202 case OP_MIPS_COND_EXC_GT_UN:
4203 case OP_MIPS_COND_EXC_LE_UN:
4204 case OP_MIPS_COND_EXC_LT_UN:
4206 case OP_MIPS_COND_EXC_OV:
4207 case OP_MIPS_COND_EXC_NO:
4208 case OP_MIPS_COND_EXC_C:
4209 case OP_MIPS_COND_EXC_NC:
4211 case OP_MIPS_COND_EXC_IEQ:
4212 case OP_MIPS_COND_EXC_IGE:
4213 case OP_MIPS_COND_EXC_IGT:
4214 case OP_MIPS_COND_EXC_ILE:
4215 case OP_MIPS_COND_EXC_ILT:
4216 case OP_MIPS_COND_EXC_INE_UN:
4217 case OP_MIPS_COND_EXC_IGE_UN:
4218 case OP_MIPS_COND_EXC_IGT_UN:
4219 case OP_MIPS_COND_EXC_ILE_UN:
4220 case OP_MIPS_COND_EXC_ILT_UN:
4222 case OP_MIPS_COND_EXC_IOV:
4223 case OP_MIPS_COND_EXC_INO:
4224 case OP_MIPS_COND_EXC_IC:
4225 case OP_MIPS_COND_EXC_INC: {
4229 /* If the condition is true, raise the exception */
4231 /* need to reverse test to skip around exception raising */
4233 /* For the moment, branch around a branch to avoid reversing
4236 /* Remember, an unpatched branch to 0 branches to the delay slot */
4237 switch (ins->opcode) {
4238 case OP_MIPS_COND_EXC_EQ:
4239 throw = (guint32 *)(void *)code;
4240 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4244 case OP_MIPS_COND_EXC_NE_UN:
4245 throw = (guint32 *)(void *)code;
4246 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4250 case OP_MIPS_COND_EXC_LE_UN:
4251 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4252 throw = (guint32 *)(void *)code;
4253 mips_beq (code, mips_at, mips_zero, 0);
4257 case OP_MIPS_COND_EXC_GT:
4258 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4259 throw = (guint32 *)(void *)code;
4260 mips_bne (code, mips_at, mips_zero, 0);
4264 case OP_MIPS_COND_EXC_GT_UN:
4265 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4266 throw = (guint32 *)(void *)code;
4267 mips_bne (code, mips_at, mips_zero, 0);
4271 case OP_MIPS_COND_EXC_LT:
4272 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4273 throw = (guint32 *)(void *)code;
4274 mips_bne (code, mips_at, mips_zero, 0);
4278 case OP_MIPS_COND_EXC_LT_UN:
4279 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4280 throw = (guint32 *)(void *)code;
4281 mips_bne (code, mips_at, mips_zero, 0);
4286 /* Not yet implemented */
4287 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4288 g_assert_not_reached ();
4290 skip = (guint32 *)(void *)code;
4291 mips_beq (code, mips_zero, mips_zero, 0);
4293 mips_patch (throw, (guint32)code);
4294 code = mips_emit_exc_by_name (code, ins->inst_p1);
4295 mips_patch (skip, (guint32)code);
4296 cfg->bb_exit->max_offset += 24;
4305 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4308 /* floating point opcodes */
4311 if (((guint32)ins->inst_p0) & (1 << 15))
4312 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4314 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4315 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4317 mips_load_const (code, mips_at, ins->inst_p0);
4318 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4319 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4323 if (((guint32)ins->inst_p0) & (1 << 15))
4324 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4326 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4327 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4328 #if PROMOTE_R4_TO_R8
4329 mips_cvtds (code, ins->dreg, ins->dreg);
4332 case OP_STORER8_MEMBASE_REG:
4333 if (mips_is_imm16 (ins->inst_offset)) {
4334 #if _MIPS_SIM == _ABIO32
4335 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4336 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4337 #elif _MIPS_SIM == _ABIN32
4338 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4341 mips_load_const (code, mips_at, ins->inst_offset);
4342 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4343 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4344 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4347 case OP_LOADR8_MEMBASE:
4348 if (mips_is_imm16 (ins->inst_offset)) {
4349 #if _MIPS_SIM == _ABIO32
4350 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4351 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4352 #elif _MIPS_SIM == _ABIN32
4353 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4356 mips_load_const (code, mips_at, ins->inst_offset);
4357 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4358 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4359 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4362 case OP_STORER4_MEMBASE_REG:
4363 g_assert (mips_is_imm16 (ins->inst_offset));
4364 #if PROMOTE_R4_TO_R8
4365 /* Need to convert ins->sreg1 to single-precision first */
4366 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4367 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4369 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4373 g_assert (mips_is_imm16 (ins->inst_offset));
4374 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4376 case OP_LOADR4_MEMBASE:
4377 g_assert (mips_is_imm16 (ins->inst_offset));
4378 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4379 #if PROMOTE_R4_TO_R8
4380 /* Convert to double precision in place */
4381 mips_cvtds (code, ins->dreg, ins->dreg);
4384 case OP_LOADR4_MEMINDEX:
4385 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4386 mips_lwc1 (code, ins->dreg, mips_at, 0);
4388 case OP_LOADR8_MEMINDEX:
4389 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4390 #if _MIPS_SIM == _ABIO32
4391 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4392 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4393 #elif _MIPS_SIM == _ABIN32
4394 mips_ldc1 (code, ins->dreg, mips_at, 0);
4397 case OP_STORER4_MEMINDEX:
4398 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4399 #if PROMOTE_R4_TO_R8
4400 /* Need to convert ins->sreg1 to single-precision first */
4401 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4402 mips_swc1 (code, mips_ftemp, mips_at, 0);
4404 mips_swc1 (code, ins->sreg1, mips_at, 0);
4407 case OP_STORER8_MEMINDEX:
4408 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4409 #if _MIPS_SIM == _ABIO32
4410 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4411 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4412 #elif _MIPS_SIM == _ABIN32
4413 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4416 case OP_ICONV_TO_R_UN: {
4417 static const guint64 adjust_val = 0x41F0000000000000ULL;
4419 /* convert unsigned int to double */
4420 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4421 mips_bgez (code, ins->sreg1, 5);
4422 mips_cvtdw (code, ins->dreg, mips_ftemp);
4424 mips_load (code, mips_at, (guint32) &adjust_val);
4425 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4426 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4427 /* target is here */
4430 case OP_ICONV_TO_R4:
4431 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4432 mips_cvtsw (code, ins->dreg, mips_ftemp);
4433 mips_cvtds (code, ins->dreg, ins->dreg);
4435 case OP_ICONV_TO_R8:
4436 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4437 mips_cvtdw (code, ins->dreg, mips_ftemp);
4439 case OP_FCONV_TO_I1:
4440 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4442 case OP_FCONV_TO_U1:
4443 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4445 case OP_FCONV_TO_I2:
4446 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4448 case OP_FCONV_TO_U2:
4449 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4451 case OP_FCONV_TO_I4:
4453 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4455 case OP_FCONV_TO_U4:
4457 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4460 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4463 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4466 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4469 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4472 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4475 mips_fnegd (code, ins->dreg, ins->sreg1);
4478 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4479 mips_addiu (code, ins->dreg, mips_zero, 1);
4480 mips_fbtrue (code, 2);
4482 MIPS_MOVE (code, ins->dreg, mips_zero);
4485 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4486 mips_addiu (code, ins->dreg, mips_zero, 1);
4487 mips_fbtrue (code, 2);
4489 MIPS_MOVE (code, ins->dreg, mips_zero);
4492 /* Less than, or Unordered */
4493 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4494 mips_addiu (code, ins->dreg, mips_zero, 1);
4495 mips_fbtrue (code, 2);
4497 MIPS_MOVE (code, ins->dreg, mips_zero);
4500 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4501 MIPS_MOVE (code, ins->dreg, mips_zero);
4502 mips_fbtrue (code, 2);
4504 mips_addiu (code, ins->dreg, mips_zero, 1);
4507 /* Greater than, or Unordered */
4508 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4509 MIPS_MOVE (code, ins->dreg, mips_zero);
4510 mips_fbtrue (code, 2);
4512 mips_addiu (code, ins->dreg, mips_zero, 1);
4517 case OP_MIPS_FBLT_UN:
4519 case OP_MIPS_FBGT_UN:
4521 case OP_MIPS_FBGE_UN:
4523 case OP_MIPS_FBLE_UN: {
4525 gboolean is_true = TRUE, is_ordered = FALSE;
4526 guint32 *buf = NULL;
4528 switch (ins->opcode) {
4542 case OP_MIPS_FBLT_UN:
4543 cond = MIPS_FPU_ULT;
4551 case OP_MIPS_FBGT_UN:
4552 cond = MIPS_FPU_OLE;
4560 case OP_MIPS_FBGE_UN:
4561 cond = MIPS_FPU_OLT;
4565 cond = MIPS_FPU_OLE;
4569 case OP_MIPS_FBLE_UN:
4570 cond = MIPS_FPU_ULE;
4574 g_assert_not_reached ();
4578 /* Skip the check if unordered */
4579 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4581 buf = (guint32*)code;
4582 mips_fbtrue (code, 0);
4586 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4588 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4590 mips_fbtrue (code, 0);
4592 mips_fbfalse (code, 0);
4596 mips_patch (buf, (guint32)code);
4600 guint32 *branch_patch;
4602 mips_mfc1 (code, mips_at, ins->sreg1+1);
4603 mips_srl (code, mips_at, mips_at, 16+4);
4604 mips_andi (code, mips_at, mips_at, 2047);
4605 mips_addiu (code, mips_at, mips_at, -2047);
4607 branch_patch = (guint32 *)(void *)code;
4608 mips_bne (code, mips_at, mips_zero, 0);
4611 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4612 mips_patch (branch_patch, (guint32)code);
4613 mips_fmovd (code, ins->dreg, ins->sreg1);
4617 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4618 mips_load (code, ins->dreg, 0x0f0f0f0f);
4623 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4624 g_assert_not_reached ();
4627 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4628 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4629 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4630 g_assert_not_reached ();
4636 last_offset = offset;
4639 cfg->code_len = code - cfg->native_code;
4643 mono_arch_register_lowlevel_calls (void)
4648 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4650 MonoJumpInfo *patch_info;
4652 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4653 unsigned char *ip = patch_info->ip.i + code;
4654 const unsigned char *target = NULL;
4656 switch (patch_info->type) {
4657 case MONO_PATCH_INFO_IP:
4658 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4660 case MONO_PATCH_INFO_SWITCH: {
4661 gpointer *table = (gpointer *)patch_info->data.table->table;
4664 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4666 for (i = 0; i < patch_info->data.table->table_size; i++) {
4667 table [i] = (int)patch_info->data.table->table [i] + code;
4671 case MONO_PATCH_INFO_METHODCONST:
4672 case MONO_PATCH_INFO_CLASS:
4673 case MONO_PATCH_INFO_IMAGE:
4674 case MONO_PATCH_INFO_FIELD:
4675 case MONO_PATCH_INFO_VTABLE:
4676 case MONO_PATCH_INFO_IID:
4677 case MONO_PATCH_INFO_SFLDA:
4678 case MONO_PATCH_INFO_LDSTR:
4679 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4680 case MONO_PATCH_INFO_LDTOKEN:
4681 case MONO_PATCH_INFO_R4:
4682 case MONO_PATCH_INFO_R8:
4683 /* from OP_AOTCONST : lui + addiu */
4684 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4685 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4688 case MONO_PATCH_INFO_EXC_NAME:
4689 g_assert_not_reached ();
4690 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4693 case MONO_PATCH_INFO_NONE:
4694 /* everything is dealt with at epilog output time */
4697 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4698 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4705 * Allow tracing to work with this interface (with an optional argument)
4707 * This code is expected to be inserted just after the 'real' prolog code,
4708 * and before the first basic block. We need to allocate a 2nd, temporary
4709 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4713 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4716 int offset = cfg->arch.tracing_offset;
4722 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4723 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4724 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4725 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4726 #if _MIPS_SIM == _ABIN32
4728 /* FIXME: Need a separate region for these */
4729 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4730 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4731 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4732 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4736 mips_load_const (code, mips_a0, cfg->method);
4737 mips_addiu (code, mips_a1, mips_sp, offset);
4738 mips_call (code, mips_t9, func);
4741 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4742 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4743 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4744 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4745 #if _MIPS_SIM == _ABIN32
4748 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4749 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4750 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4751 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4762 mips_adjust_stackframe(MonoCompile *cfg)
4765 int delta, threshold, i;
4766 MonoMethodSignature *sig;
4769 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4772 /* adjust cfg->stack_offset for account for down-spilling */
4773 cfg->stack_offset += SIZEOF_REGISTER;
4775 /* re-align cfg->stack_offset if needed (due to var spilling) */
4776 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4777 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4778 if (cfg->verbose_level > 2) {
4779 g_print ("mips_adjust_stackframe:\n");
4780 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4782 threshold = cfg->arch.local_alloc_offset;
4783 ra_offset = cfg->stack_offset - sizeof(gpointer);
4784 if (cfg->verbose_level > 2) {
4785 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4788 sig = mono_method_signature (cfg->method);
4789 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4790 cfg->vret_addr->inst_offset += delta;
4792 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4793 MonoInst *inst = cfg->args [i];
4795 inst->inst_offset += delta;
4799 * loads and stores based off the frame reg that (used to) lie
4800 * above the spill var area need to be increased by 'delta'
4801 * to make room for the spill vars.
4803 /* Need to find loads and stores to adjust that
4804 * are above where the spillvars were inserted, but
4805 * which are not the spillvar references themselves.
4807 * Idea - since all offsets from fp are positive, make
4808 * spillvar offsets negative to begin with so we can spot
4813 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4817 if (cfg->verbose_level > 2) {
4818 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4820 MONO_BB_FOR_EACH_INS (bb, ins) {
4824 if (cfg->verbose_level > 2) {
4825 mono_print_ins_index (ins_cnt, ins);
4827 /* The == mips_sp tests catch FP spills */
4828 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4829 (ins->inst_basereg == mips_sp))) {
4830 switch (ins->opcode) {
4831 case OP_LOADI8_MEMBASE:
4832 case OP_LOADR8_MEMBASE:
4839 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4840 (ins->dreg == mips_sp))) {
4841 switch (ins->opcode) {
4842 case OP_STOREI8_MEMBASE_REG:
4843 case OP_STORER8_MEMBASE_REG:
4844 case OP_STOREI8_MEMBASE_IMM:
4852 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4855 if (ins->inst_c0 >= threshold) {
4856 ins->inst_c0 += delta;
4857 if (cfg->verbose_level > 2) {
4859 mono_print_ins_index (ins_cnt, ins);
4862 else if (ins->inst_c0 < 0) {
4863 /* Adj_c0 holds the size of the datatype. */
4864 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4865 if (cfg->verbose_level > 2) {
4867 mono_print_ins_index (ins_cnt, ins);
4870 g_assert (ins->inst_c0 != ra_offset);
4873 if (ins->inst_imm >= threshold) {
4874 ins->inst_imm += delta;
4875 if (cfg->verbose_level > 2) {
4877 mono_print_ins_index (ins_cnt, ins);
4880 g_assert (ins->inst_c0 != ra_offset);
4890 * Stack frame layout:
4892 * ------------------- sp + cfg->stack_usage + cfg->param_area
4893 * param area incoming
4894 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4896 * ------------------- sp + cfg->stack_usage
4898 * ------------------- sp + cfg->stack_usage-4
4900 * ------------------- sp +
4901 * MonoLMF structure optional
4902 * ------------------- sp + cfg->arch.lmf_offset
4903 * saved registers s0-s8
4904 * ------------------- sp + cfg->arch.iregs_offset
4906 * ------------------- sp + cfg->param_area
4907 * param area outgoing
4908 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4910 * ------------------- sp
4914 mono_arch_emit_prolog (MonoCompile *cfg)
4916 MonoMethod *method = cfg->method;
4917 MonoMethodSignature *sig;
4919 int alloc_size, pos, i, max_offset;
4920 int alloc2_size = 0;
4924 guint32 iregs_to_save = 0;
4926 guint32 fregs_to_save = 0;
4928 /* lmf_offset is the offset of the LMF from our stack pointer. */
4929 guint32 lmf_offset = cfg->arch.lmf_offset;
4933 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4937 cfg->flags |= MONO_CFG_HAS_CALLS;
4939 sig = mono_method_signature (method);
4940 cfg->code_size = 768 + sig->param_count * 20;
4941 code = cfg->native_code = g_malloc (cfg->code_size);
4944 * compute max_offset in order to use short forward jumps.
4947 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4948 MonoInst *ins = bb->code;
4949 bb->max_offset = max_offset;
4951 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4954 MONO_BB_FOR_EACH_INS (bb, ins)
4955 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4957 if (max_offset > 0xffff)
4958 cfg->arch.long_branch = TRUE;
4961 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4962 * This means that we have to adjust the offsets inside instructions which reference
4963 * arguments received on the stack, since the initial offset doesn't take into
4964 * account spill slots.
4966 mips_adjust_stackframe (cfg);
4968 /* Offset between current sp and the CFA */
4970 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4972 /* stack_offset should not be changed here. */
4973 alloc_size = cfg->stack_offset;
4974 cfg->stack_usage = alloc_size;
4976 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4979 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4981 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4982 fregs_to_save |= (fregs_to_save << 1);
4985 /* If the stack size is too big, save 1024 bytes to start with
4986 * so the prologue can use imm16(reg) addressing, then allocate
4987 * the rest of the frame.
4989 if (alloc_size > ((1 << 15) - 1024)) {
4990 alloc2_size = alloc_size - 1024;
4994 g_assert (mips_is_imm16 (-alloc_size));
4995 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4996 cfa_offset = alloc_size;
4997 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5000 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5001 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5002 if (mips_is_imm16(offset))
5003 mips_sw (code, mips_ra, mips_sp, offset);
5005 g_assert_not_reached ();
5007 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5008 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5011 /* XXX - optimize this later to not save all regs if LMF constructed */
5012 pos = cfg->arch.iregs_offset - alloc2_size;
5014 if (iregs_to_save) {
5015 /* save used registers in own stack frame (at pos) */
5016 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5017 if (iregs_to_save & (1 << i)) {
5018 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5019 g_assert (mips_is_imm16(pos));
5020 MIPS_SW (code, i, mips_sp, pos);
5021 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5022 pos += SIZEOF_REGISTER;
5027 // FIXME: Don't save registers twice if there is an LMF
5028 // s8 has to be special cased since it is overwritten with the updated value
5030 if (method->save_lmf) {
5031 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5032 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5033 g_assert (mips_is_imm16(offset));
5034 if (MIPS_LMF_IREGMASK & (1 << i))
5035 MIPS_SW (code, i, mips_sp, offset);
5040 /* Save float registers */
5041 if (fregs_to_save) {
5042 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5043 if (fregs_to_save & (1 << i)) {
5044 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5045 g_assert (mips_is_imm16(pos));
5046 mips_swc1 (code, i, mips_sp, pos);
5047 pos += sizeof (gulong);
5052 if (method->save_lmf) {
5053 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5054 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5055 g_assert (mips_is_imm16(offset));
5056 mips_swc1 (code, i, mips_sp, offset);
5061 if (cfg->frame_reg != mips_sp) {
5062 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5063 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5065 if (method->save_lmf) {
5066 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5067 g_assert (mips_is_imm16(offset));
5068 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5072 /* store runtime generic context */
5073 if (cfg->rgctx_var) {
5074 MonoInst *ins = cfg->rgctx_var;
5076 g_assert (ins->opcode == OP_REGOFFSET);
5078 g_assert (mips_is_imm16 (ins->inst_offset));
5079 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5082 /* load arguments allocated to register from the stack */
5085 if (!cfg->arch.cinfo)
5086 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
5087 cinfo = cfg->arch.cinfo;
5089 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5090 ArgInfo *ainfo = &cinfo->ret;
5091 inst = cfg->vret_addr;
5092 if (inst->opcode == OP_REGVAR)
5093 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5094 else if (mips_is_imm16 (inst->inst_offset)) {
5095 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5097 mips_load_const (code, mips_at, inst->inst_offset);
5098 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5099 mips_sw (code, ainfo->reg, mips_at, 0);
5103 if (sig->call_convention == MONO_CALL_VARARG) {
5104 ArgInfo *cookie = &cinfo->sig_cookie;
5105 int offset = alloc_size + cookie->offset;
5107 /* Save the sig cookie address */
5108 g_assert (cookie->storage == ArgOnStack);
5110 g_assert (mips_is_imm16(offset));
5111 mips_addi (code, mips_at, cfg->frame_reg, offset);
5112 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5115 /* Keep this in sync with emit_load_volatile_arguments */
5116 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5117 ArgInfo *ainfo = cinfo->args + i;
5118 inst = cfg->args [pos];
5120 if (cfg->verbose_level > 2)
5121 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5122 if (inst->opcode == OP_REGVAR) {
5123 /* Argument ends up in a register */
5124 if (ainfo->storage == ArgInIReg)
5125 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5126 else if (ainfo->storage == ArgInFReg) {
5127 g_assert_not_reached();
5129 ppc_fmr (code, inst->dreg, ainfo->reg);
5132 else if (ainfo->storage == ArgOnStack) {
5133 int offset = cfg->stack_usage + ainfo->offset;
5134 g_assert (mips_is_imm16(offset));
5135 mips_lw (code, inst->dreg, mips_sp, offset);
5137 g_assert_not_reached ();
5139 if (cfg->verbose_level > 2)
5140 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5142 /* Argument ends up on the stack */
5143 if (ainfo->storage == ArgInIReg) {
5145 /* Incoming parameters should be above this frame */
5146 if (cfg->verbose_level > 2)
5147 g_print ("stack slot at %d of %d+%d\n",
5148 inst->inst_offset, alloc_size, alloc2_size);
5149 /* g_assert (inst->inst_offset >= alloc_size); */
5150 g_assert (inst->inst_basereg == cfg->frame_reg);
5151 basereg_offset = inst->inst_offset - alloc2_size;
5152 g_assert (mips_is_imm16 (basereg_offset));
5153 switch (ainfo->size) {
5155 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5158 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5162 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5165 #if (SIZEOF_REGISTER == 4)
5166 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5167 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5168 #elif (SIZEOF_REGISTER == 8)
5169 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5173 g_assert_not_reached ();
5176 } else if (ainfo->storage == ArgOnStack) {
5178 * Argument comes in on the stack, and ends up on the stack
5179 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5180 * 8 and 16 bit quantities. Shorten them in place.
5182 g_assert (mips_is_imm16 (inst->inst_offset));
5183 switch (ainfo->size) {
5185 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5186 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5189 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5190 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5197 g_assert_not_reached ();
5199 } else if (ainfo->storage == ArgInFReg) {
5200 g_assert (mips_is_imm16 (inst->inst_offset));
5201 g_assert (mips_is_imm16 (inst->inst_offset+4));
5202 if (ainfo->size == 8) {
5203 #if _MIPS_SIM == _ABIO32
5204 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5205 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5206 #elif _MIPS_SIM == _ABIN32
5207 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5210 else if (ainfo->size == 4)
5211 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5213 g_assert_not_reached ();
5214 } else if (ainfo->storage == ArgStructByVal) {
5216 int doffset = inst->inst_offset;
5218 g_assert (mips_is_imm16 (inst->inst_offset));
5219 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5220 /* Push the argument registers into their stack slots */
5221 for (i = 0; i < ainfo->size; ++i) {
5222 g_assert (mips_is_imm16(doffset));
5223 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5224 doffset += SIZEOF_REGISTER;
5226 } else if (ainfo->storage == ArgStructByAddr) {
5227 g_assert (mips_is_imm16 (inst->inst_offset));
5228 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5229 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5231 g_assert_not_reached ();
5236 if (method->save_lmf) {
5237 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5238 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5240 if (lmf_pthread_key != -1) {
5241 g_assert_not_reached();
5243 emit_tls_access (code, mips_temp, lmf_pthread_key);
5245 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5246 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5247 g_assert (mips_is_imm16(offset));
5248 mips_addiu (code, mips_a0, mips_temp, offset);
5251 /* This can/will clobber the a0-a3 registers */
5252 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5255 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5256 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5257 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5258 /* new_lmf->previous_lmf = *lmf_addr */
5259 mips_lw (code, mips_at, mips_v0, 0);
5260 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5261 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5262 /* *(lmf_addr) = sp + lmf_offset */
5263 g_assert (mips_is_imm16(lmf_offset));
5264 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5265 mips_sw (code, mips_at, mips_v0, 0);
5267 /* save method info */
5268 mips_load_const (code, mips_at, method);
5269 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5270 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5272 /* save the current IP */
5273 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5274 mips_load_const (code, mips_at, 0x01010101);
5275 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5279 if (mips_is_imm16 (-alloc2_size)) {
5280 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5283 mips_load_const (code, mips_at, -alloc2_size);
5284 mips_addu (code, mips_sp, mips_sp, mips_at);
5286 alloc_size += alloc2_size;
5287 cfa_offset += alloc2_size;
5288 if (cfg->frame_reg != mips_sp)
5289 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5291 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5295 #if _MIPS_SIM == _ABIO32
5296 cfg->arch.tracing_offset = cfg->stack_offset;
5297 #elif _MIPS_SIM == _ABIN32
5298 /* no stack slots by default for argument regs, reserve a special block */
5299 g_assert_not_reached ();
5301 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5304 cfg->code_len = code - cfg->native_code;
5305 g_assert (cfg->code_len < cfg->code_size);
5319 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5322 int save_mode = SAVE_NONE;
5324 MonoMethod *method = cfg->method;
5325 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type;
5326 int save_offset = MIPS_STACK_PARAM_OFFSET;
5328 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5330 offset = code - cfg->native_code;
5331 /* we need about 16 instructions */
5332 if (offset > (cfg->code_size - 16 * 4)) {
5333 cfg->code_size *= 2;
5334 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5335 code = cfg->native_code + offset;
5340 case MONO_TYPE_VOID:
5341 /* special case string .ctor icall */
5342 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5343 save_mode = SAVE_ONE;
5345 save_mode = SAVE_NONE;
5349 save_mode = SAVE_FP;
5351 case MONO_TYPE_VALUETYPE:
5352 save_mode = SAVE_STRUCT;
5356 #if SIZEOF_REGISTER == 4
5357 save_mode = SAVE_TWO;
5358 #elif SIZEOF_REGISTER == 8
5359 save_mode = SAVE_ONE;
5363 save_mode = SAVE_ONE;
5367 mips_addiu (code, mips_sp, mips_sp, -32);
5368 g_assert (mips_is_imm16(save_offset));
5369 switch (save_mode) {
5371 mips_sw (code, mips_v0, mips_sp, save_offset);
5372 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5373 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5374 if (enable_arguments) {
5375 MIPS_MOVE (code, mips_a1, mips_v0);
5376 MIPS_MOVE (code, mips_a2, mips_v1);
5380 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5381 if (enable_arguments) {
5382 MIPS_MOVE (code, mips_a1, mips_v0);
5386 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5387 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5388 mips_lw (code, mips_a0, mips_sp, save_offset);
5389 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5390 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5397 mips_load_const (code, mips_a0, cfg->method);
5398 mips_call (code, mips_t9, func);
5400 switch (save_mode) {
5402 mips_lw (code, mips_v0, mips_sp, save_offset);
5403 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5404 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5407 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5410 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5417 mips_addiu (code, mips_sp, mips_sp, 32);
5424 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5426 MonoMethod *method = cfg->method;
5428 int max_epilog_size = 16 + 20*4;
5429 int alloc2_size = 0;
5430 guint32 iregs_to_restore;
5432 guint32 fregs_to_restore;
5435 if (cfg->method->save_lmf)
5436 max_epilog_size += 128;
5438 if (mono_jit_trace_calls != NULL)
5439 max_epilog_size += 50;
5441 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5442 max_epilog_size += 50;
5445 pos = code - cfg->native_code;
5446 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5447 cfg->code_size *= 2;
5448 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5449 cfg->stat_code_reallocs++;
5453 * Keep in sync with OP_JMP
5456 code = cfg->native_code + pos;
5458 code = cfg->native_code + cfg->code_len;
5460 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5461 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5463 if (cfg->frame_reg != mips_sp) {
5464 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5466 /* If the stack frame is really large, deconstruct it in two steps */
5467 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5468 alloc2_size = cfg->stack_usage - 1024;
5469 /* partially deconstruct the stack */
5470 mips_load_const (code, mips_at, alloc2_size);
5471 mips_addu (code, mips_sp, mips_sp, mips_at);
5473 pos = cfg->arch.iregs_offset - alloc2_size;
5474 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5475 if (iregs_to_restore) {
5476 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5477 if (iregs_to_restore & (1 << i)) {
5478 g_assert (mips_is_imm16(pos));
5479 MIPS_LW (code, i, mips_sp, pos);
5480 pos += SIZEOF_REGISTER;
5487 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5489 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5490 fregs_to_restore |= (fregs_to_restore << 1);
5492 if (fregs_to_restore) {
5493 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5494 if (fregs_to_restore & (1 << i)) {
5495 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5496 g_assert (mips_is_imm16(pos));
5497 mips_lwc1 (code, i, mips_sp, pos);
5504 /* Unlink the LMF if necessary */
5505 if (method->save_lmf) {
5506 int lmf_offset = cfg->arch.lmf_offset;
5508 /* t0 = current_lmf->previous_lmf */
5509 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5510 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5512 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5513 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5514 /* (*lmf_addr) = previous_lmf */
5515 mips_sw (code, mips_temp, mips_t1, 0);
5519 /* Restore the fp */
5520 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5523 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5524 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5525 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5527 /* Restore the stack pointer */
5528 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5529 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5531 /* Caller will emit either return or tail-call sequence */
5533 cfg->code_len = code - cfg->native_code;
5535 g_assert (cfg->code_len < cfg->code_size);
5540 mono_arch_emit_epilog (MonoCompile *cfg)
5544 code = mono_arch_emit_epilog_sub (cfg, NULL);
5546 mips_jr (code, mips_ra);
5549 cfg->code_len = code - cfg->native_code;
5551 g_assert (cfg->code_len < cfg->code_size);
5554 /* remove once throw_exception_by_name is eliminated */
5557 exception_id_by_name (const char *name)
5559 if (strcmp (name, "IndexOutOfRangeException") == 0)
5560 return MONO_EXC_INDEX_OUT_OF_RANGE;
5561 if (strcmp (name, "OverflowException") == 0)
5562 return MONO_EXC_OVERFLOW;
5563 if (strcmp (name, "ArithmeticException") == 0)
5564 return MONO_EXC_ARITHMETIC;
5565 if (strcmp (name, "DivideByZeroException") == 0)
5566 return MONO_EXC_DIVIDE_BY_ZERO;
5567 if (strcmp (name, "InvalidCastException") == 0)
5568 return MONO_EXC_INVALID_CAST;
5569 if (strcmp (name, "NullReferenceException") == 0)
5570 return MONO_EXC_NULL_REF;
5571 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5572 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5573 if (strcmp (name, "ArgumentException") == 0)
5574 return MONO_EXC_ARGUMENT;
5575 g_error ("Unknown intrinsic exception %s\n", name);
5581 mono_arch_emit_exceptions (MonoCompile *cfg)
5584 MonoJumpInfo *patch_info;
5587 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5588 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5589 int max_epilog_size = 50;
5591 /* count the number of exception infos */
5594 * make sure we have enough space for exceptions
5595 * 24 is the simulated call to throw_exception_by_name
5597 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5599 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5600 i = exception_id_by_name (patch_info->data.target);
5601 g_assert (i < MONO_EXC_INTRINS_NUM);
5602 if (!exc_throw_found [i]) {
5603 max_epilog_size += 12;
5604 exc_throw_found [i] = TRUE;
5610 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5611 cfg->code_size *= 2;
5612 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5613 cfg->stat_code_reallocs++;
5616 code = cfg->native_code + cfg->code_len;
5618 /* add code to raise exceptions */
5619 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5620 switch (patch_info->type) {
5621 case MONO_PATCH_INFO_EXC: {
5623 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5625 i = exception_id_by_name (patch_info->data.target);
5626 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5627 if (!exc_throw_pos [i]) {
5630 exc_throw_pos [i] = code;
5631 //g_print ("exc: writing stub at %p\n", code);
5632 mips_load_const (code, mips_a0, patch_info->data.target);
5633 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5634 mips_load_const (code, mips_t9, addr);
5635 mips_jr (code, mips_t9);
5638 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5640 /* Turn into a Relative patch, pointing at code stub */
5641 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5642 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5644 g_assert_not_reached();
5654 cfg->code_len = code - cfg->native_code;
5656 g_assert (cfg->code_len < cfg->code_size);
5661 * Thread local storage support
5664 setup_tls_access (void)
5667 //guint32 *ins, *code;
5669 if (tls_mode == TLS_MODE_FAILED)
5672 if (g_getenv ("MONO_NO_TLS")) {
5673 tls_mode = TLS_MODE_FAILED;
5677 if (tls_mode == TLS_MODE_DETECT) {
5679 tls_mode = TLS_MODE_FAILED;
5683 ins = (guint32*)pthread_getspecific;
5684 /* uncond branch to the real method */
5685 if ((*ins >> 26) == 18) {
5687 val = (*ins & ~3) << 6;
5691 ins = (guint32*)val;
5693 ins = (guint32*) ((char*)ins + val);
5696 code = &cmplwi_1023;
5697 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5699 ppc_li (code, ppc_r4, 0x48);
5702 if (*ins == cmplwi_1023) {
5703 int found_lwz_284 = 0;
5704 for (ptk = 0; ptk < 20; ++ptk) {
5706 if (!*ins || *ins == blr_ins)
5708 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5713 if (!found_lwz_284) {
5714 tls_mode = TLS_MODE_FAILED;
5717 tls_mode = TLS_MODE_LTHREADS;
5718 } else if (*ins == li_0x48) {
5720 /* uncond branch to the real method */
5721 if ((*ins >> 26) == 18) {
5723 val = (*ins & ~3) << 6;
5727 ins = (guint32*)val;
5729 ins = (guint32*) ((char*)ins + val);
5732 ppc_li (code, ppc_r0, 0x7FF2);
5733 if (ins [1] == val) {
5734 /* Darwin on G4, implement */
5735 tls_mode = TLS_MODE_FAILED;
5739 ppc_mfspr (code, ppc_r3, 104);
5740 if (ins [1] != val) {
5741 tls_mode = TLS_MODE_FAILED;
5744 tls_mode = TLS_MODE_DARWIN_G5;
5747 tls_mode = TLS_MODE_FAILED;
5751 tls_mode = TLS_MODE_FAILED;
5756 if (monodomain_key == -1) {
5757 ptk = mono_domain_get_tls_key ();
5759 monodomain_key = ptk;
5761 if (lmf_pthread_key == -1) {
5762 ptk = mono_jit_tls_id;
5764 /*g_print ("MonoLMF at: %d\n", ptk);*/
5765 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5766 init_tls_failed = 1;
5769 lmf_pthread_key = ptk;
5772 if (monothread_key == -1) {
5773 ptk = mono_thread_get_tls_key ();
5775 monothread_key = ptk;
5776 /*g_print ("thread inited: %d\n", ptk);*/
5778 /*g_print ("thread not inited yet %d\n", ptk);*/
5784 mono_arch_finish_init (void)
5786 setup_tls_access ();
5790 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5795 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5797 int this_dreg = mips_a0;
5800 this_dreg = mips_a1;
5802 /* add the this argument */
5803 if (this_reg != -1) {
5805 MONO_INST_NEW (cfg, this, OP_MOVE);
5806 this->type = this_type;
5807 this->sreg1 = this_reg;
5808 this->dreg = mono_alloc_ireg (cfg);
5809 mono_bblock_add_inst (cfg->cbb, this);
5810 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5815 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5816 vtarg->type = STACK_MP;
5817 vtarg->sreg1 = vt_reg;
5818 vtarg->dreg = mono_alloc_ireg (cfg);
5819 mono_bblock_add_inst (cfg->cbb, vtarg);
5820 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5825 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5827 MonoInst *ins = NULL;
5833 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5839 mono_arch_print_tree (MonoInst *tree, int arity)
5844 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5848 setup_tls_access ();
5849 if (monodomain_key == -1)
5852 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5853 ins->inst_offset = monodomain_key;
5858 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5860 return ctx->sc_regs [reg];
5863 #ifdef MONO_ARCH_HAVE_IMT
5865 #define ENABLE_WRONG_METHOD_CHECK 0
5867 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5868 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5870 #define LOADSTORE_SIZE 4
5871 #define JUMP_IMM_SIZE 16
5872 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5873 #define LOAD_CONST_SIZE 8
5874 #define JUMP_JR_SIZE 8
5877 * LOCKING: called with the domain lock held
5880 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5881 gpointer fail_tramp)
5885 guint8 *code, *start, *patch;
5887 for (i = 0; i < count; ++i) {
5888 MonoIMTCheckItem *item = imt_entries [i];
5890 if (item->is_equals) {
5891 if (item->check_target_idx) {
5892 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5893 if (item->has_target_code)
5894 item->chunk_size += LOAD_CONST_SIZE;
5896 item->chunk_size += LOADSTORE_SIZE;
5899 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5900 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5901 if (!item->has_target_code)
5902 item->chunk_size += LOADSTORE_SIZE;
5904 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5905 #if ENABLE_WRONG_METHOD_CHECK
5906 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5911 item->chunk_size += CMP_SIZE + BR_SIZE;
5912 imt_entries [item->check_target_idx]->compare_done = TRUE;
5914 size += item->chunk_size;
5916 /* the initial load of the vtable address */
5917 size += MIPS_LOAD_SEQUENCE_LENGTH;
5919 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5921 code = mono_domain_code_reserve (domain, size);
5925 /* t7 points to the vtable */
5926 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5928 for (i = 0; i < count; ++i) {
5929 MonoIMTCheckItem *item = imt_entries [i];
5931 item->code_target = code;
5932 if (item->is_equals) {
5933 if (item->check_target_idx) {
5934 mips_load_const (code, mips_temp, (gsize)item->key);
5935 item->jmp_code = code;
5936 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5938 if (item->has_target_code) {
5939 mips_load_const (code, mips_t9,
5940 item->value.target_code);
5943 mips_lw (code, mips_t9, mips_t7,
5944 (sizeof (gpointer) * item->value.vtable_slot));
5946 mips_jr (code, mips_t9);
5950 mips_load_const (code, mips_temp, (gsize)item->key);
5952 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5954 if (item->has_target_code) {
5955 mips_load_const (code, mips_t9,
5956 item->value.target_code);
5959 mips_load_const (code, mips_at,
5960 & (vtable->vtable [item->value.vtable_slot]));
5961 mips_lw (code, mips_t9, mips_at, 0);
5963 mips_jr (code, mips_t9);
5965 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5966 mips_load_const (code, mips_t9, fail_tramp);
5967 mips_jr (code, mips_t9);
5970 /* enable the commented code to assert on wrong method */
5971 #if ENABLE_WRONG_METHOD_CHECK
5972 ppc_load (code, ppc_r0, (guint32)item->key);
5973 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5975 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5977 mips_lw (code, mips_t9, mips_t7,
5978 (sizeof (gpointer) * item->value.vtable_slot));
5979 mips_jr (code, mips_t9);
5982 #if ENABLE_WRONG_METHOD_CHECK
5983 ppc_patch (patch, code);
5989 mips_load_const (code, mips_temp, (gulong)item->key);
5990 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5992 item->jmp_code = code;
5993 mips_beq (code, mips_temp, mips_zero, 0);
5997 /* patch the branches to get to the target items */
5998 for (i = 0; i < count; ++i) {
5999 MonoIMTCheckItem *item = imt_entries [i];
6000 if (item->jmp_code && item->check_target_idx) {
6001 mips_patch ((guint32 *)item->jmp_code,
6002 (guint32)imt_entries [item->check_target_idx]->code_target);
6007 mono_stats.imt_thunks_size += code - start;
6008 g_assert (code - start <= size);
6009 mono_arch_flush_icache (start, size);
6014 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6016 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6021 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6023 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6026 /* Soft Debug support */
6027 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6030 * mono_arch_set_breakpoint:
6032 * See mini-amd64.c for docs.
6035 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6038 guint32 addr = (guint32)bp_trigger_page;
6040 mips_load_const (code, mips_t9, addr);
6041 mips_lw (code, mips_t9, mips_t9, 0);
6043 mono_arch_flush_icache (ip, code - ip);
6047 * mono_arch_clear_breakpoint:
6049 * See mini-amd64.c for docs.
6052 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6060 mono_arch_flush_icache (ip, code - ip);
6064 * mono_arch_start_single_stepping:
6066 * See mini-amd64.c for docs.
6069 mono_arch_start_single_stepping (void)
6071 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6075 * mono_arch_stop_single_stepping:
6077 * See mini-amd64.c for docs.
6080 mono_arch_stop_single_stepping (void)
6082 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6086 * mono_arch_is_single_step_event:
6088 * See mini-amd64.c for docs.
6091 mono_arch_is_single_step_event (void *info, void *sigctx)
6093 siginfo_t* sinfo = (siginfo_t*) info;
6094 /* Sometimes the address is off by 4 */
6095 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6102 * mono_arch_is_breakpoint_event:
6104 * See mini-amd64.c for docs.
6107 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6109 siginfo_t* sinfo = (siginfo_t*) info;
6110 /* Sometimes the address is off by 4 */
6111 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6118 * mono_arch_skip_breakpoint:
6120 * See mini-amd64.c for docs.
6123 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6125 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6129 * mono_arch_skip_single_step:
6131 * See mini-amd64.c for docs.
6134 mono_arch_skip_single_step (MonoContext *ctx)
6136 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6140 * mono_arch_get_seq_point_info:
6142 * See mini-amd64.c for docs.
6145 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6151 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */