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/abi-details.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/utils/mono-mmap.h>
22 #include <mono/utils/mono-hwcap-mips.h>
24 #include <mono/arch/mips/mips-codegen.h>
26 #include "mini-mips.h"
31 #define SAVE_FP_REGS 0
33 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
35 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
36 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
37 remember to update cpu-mips.md if you change this */
39 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
40 #define mips_call(c,D,v) do { \
41 guint32 _target = (guint32)(v); \
42 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
43 mips_load_const (c, D, _target); \
44 mips_jalr (c, D, mips_ra); \
47 mips_jumpl (c, _target >> 2); \
59 /* This mutex protects architecture specific caches */
60 #define mono_mini_arch_lock() mono_mutex_lock (&mini_arch_mutex)
61 #define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
62 static mono_mutex_t mini_arch_mutex;
64 int mono_exc_esp_offset = 0;
65 static int tls_mode = TLS_MODE_DETECT;
66 static int lmf_pthread_key = -1;
67 static int monothread_key = -1;
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 (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 (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 (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
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, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
556 mips_lw (code, mips_a0, mips_a0, MONO_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, MONO_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 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
585 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
586 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
594 * mono_arch_get_delegate_invoke_impls:
596 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
600 mono_arch_get_delegate_invoke_impls (void)
606 get_delegate_invoke_impl (&info, TRUE, 0);
607 res = g_slist_prepend (res, info);
609 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
610 get_delegate_invoke_impl (&info, FALSE, i);
611 res = g_slist_prepend (res, info);
618 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
620 guint8 *code, *start;
622 /* FIXME: Support more cases */
623 if (MONO_TYPE_ISSTRUCT (sig->ret))
627 static guint8* cached = NULL;
628 mono_mini_arch_lock ();
630 mono_mini_arch_unlock ();
635 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
638 start = get_delegate_invoke_impl (&info, TRUE, 0);
639 mono_tramp_info_register (info, NULL);
642 mono_mini_arch_unlock ();
645 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
648 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
650 for (i = 0; i < sig->param_count; ++i)
651 if (!mono_is_regsize_var (sig->params [i]))
654 mono_mini_arch_lock ();
655 code = cache [sig->param_count];
657 mono_mini_arch_unlock ();
662 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
663 start = mono_aot_get_trampoline (name);
667 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
668 mono_tramp_info_register (info, NULL);
670 cache [sig->param_count] = start;
671 mono_mini_arch_unlock ();
679 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
685 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
688 return (gpointer)regs [mips_a0];
692 * Initialize the cpu to execute managed code.
695 mono_arch_cpu_init (void)
697 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
706 ls_word_offset = ls_word_idx * 4;
707 ms_word_offset = ms_word_idx * 4;
711 * Initialize architecture specific code.
714 mono_arch_init (void)
716 mono_mutex_init_recursive (&mini_arch_mutex);
718 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
719 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
720 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
724 * Cleanup architecture specific code.
727 mono_arch_cleanup (void)
729 mono_mutex_destroy (&mini_arch_mutex);
733 * This function returns the optimizations supported on this cpu.
736 mono_arch_cpu_optimizations (guint32 *exclude_mask)
740 /* no mips-specific optimizations yet */
746 * This function test for all SIMD functions supported.
748 * Returns a bitmask corresponding to all supported versions.
752 mono_arch_cpu_enumerate_simd_versions (void)
754 /* SIMD is currently unimplemented */
759 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
764 for (i = 0; i < cfg->num_varinfo; i++) {
765 MonoInst *ins = cfg->varinfo [i];
766 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
769 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
772 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
775 /* we can only allocate 32 bit values */
776 if (mono_is_regsize_var (ins->inst_vtype)) {
777 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
778 g_assert (i == vmv->idx);
779 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
787 mono_arch_get_global_int_regs (MonoCompile *cfg)
791 regs = g_list_prepend (regs, (gpointer)mips_s0);
792 regs = g_list_prepend (regs, (gpointer)mips_s1);
793 regs = g_list_prepend (regs, (gpointer)mips_s2);
794 regs = g_list_prepend (regs, (gpointer)mips_s3);
795 regs = g_list_prepend (regs, (gpointer)mips_s4);
796 //regs = g_list_prepend (regs, (gpointer)mips_s5);
797 regs = g_list_prepend (regs, (gpointer)mips_s6);
798 regs = g_list_prepend (regs, (gpointer)mips_s7);
804 * mono_arch_regalloc_cost:
806 * Return the cost, in number of memory references, of the action of
807 * allocating the variable VMV into a register during global register
811 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
818 args_onto_stack (CallInfo *info)
820 g_assert (!info->on_stack);
821 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
822 info->on_stack = TRUE;
823 info->stack_size = MIPS_STACK_PARAM_OFFSET;
826 #if _MIPS_SIM == _ABIO32
828 * O32 calling convention version
832 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
833 /* First, see if we need to drop onto the stack */
834 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
835 args_onto_stack (info);
837 /* Now, place the argument */
838 if (info->on_stack) {
839 ainfo->storage = ArgOnStack;
840 ainfo->reg = mips_sp; /* in the caller */
841 ainfo->offset = info->stack_size;
844 ainfo->storage = ArgInIReg;
845 ainfo->reg = info->gr;
847 info->gr_passed = TRUE;
849 info->stack_size += 4;
853 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
854 /* First, see if we need to drop onto the stack */
855 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
856 args_onto_stack (info);
858 /* Now, place the argument */
859 if (info->on_stack) {
860 g_assert (info->stack_size % 4 == 0);
861 info->stack_size += (info->stack_size % 8);
863 ainfo->storage = ArgOnStack;
864 ainfo->reg = mips_sp; /* in the caller */
865 ainfo->offset = info->stack_size;
868 // info->gr must be a0 or a2
869 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
870 g_assert(info->gr <= MIPS_LAST_ARG_REG);
872 ainfo->storage = ArgInIReg;
873 ainfo->reg = info->gr;
875 info->gr_passed = TRUE;
877 info->stack_size += 8;
881 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
882 /* First, see if we need to drop onto the stack */
883 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
884 args_onto_stack (info);
886 /* Now, place the argument */
887 if (info->on_stack) {
888 ainfo->storage = ArgOnStack;
889 ainfo->reg = mips_sp; /* in the caller */
890 ainfo->offset = info->stack_size;
893 /* Only use FP regs for args if no int args passed yet */
894 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
895 ainfo->storage = ArgInFReg;
896 ainfo->reg = info->fr;
897 /* Even though it's a single-precision float, it takes up two FP regs */
899 /* FP and GP slots do not overlap */
903 /* Passing single-precision float arg in a GP register
904 * such as: func (0, 1.0, 2, 3);
905 * In this case, only one 'gr' register is consumed.
907 ainfo->storage = ArgInIReg;
908 ainfo->reg = info->gr;
911 info->gr_passed = TRUE;
914 info->stack_size += 4;
918 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
919 /* First, see if we need to drop onto the stack */
920 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
921 args_onto_stack (info);
923 /* Now, place the argument */
924 if (info->on_stack) {
925 g_assert(info->stack_size % 4 == 0);
926 info->stack_size += (info->stack_size % 8);
928 ainfo->storage = ArgOnStack;
929 ainfo->reg = mips_sp; /* in the caller */
930 ainfo->offset = info->stack_size;
933 /* Only use FP regs for args if no int args passed yet */
934 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
935 ainfo->storage = ArgInFReg;
936 ainfo->reg = info->fr;
938 /* FP and GP slots do not overlap */
942 // info->gr must be a0 or a2
943 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
944 g_assert(info->gr <= MIPS_LAST_ARG_REG);
946 ainfo->storage = ArgInIReg;
947 ainfo->reg = info->gr;
949 info->gr_passed = TRUE;
952 info->stack_size += 8;
954 #elif _MIPS_SIM == _ABIN32
956 * N32 calling convention version
960 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
961 /* First, see if we need to drop onto the stack */
962 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
963 args_onto_stack (info);
965 /* Now, place the argument */
966 if (info->on_stack) {
967 ainfo->storage = ArgOnStack;
968 ainfo->reg = mips_sp; /* in the caller */
969 ainfo->offset = info->stack_size;
970 info->stack_size += SIZEOF_REGISTER;
973 ainfo->storage = ArgInIReg;
974 ainfo->reg = info->gr;
976 info->gr_passed = TRUE;
981 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
982 /* First, see if we need to drop onto the stack */
983 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
984 args_onto_stack (info);
986 /* Now, place the argument */
987 if (info->on_stack) {
988 g_assert (info->stack_size % 4 == 0);
989 info->stack_size += (info->stack_size % 8);
991 ainfo->storage = ArgOnStack;
992 ainfo->reg = mips_sp; /* in the caller */
993 ainfo->offset = info->stack_size;
994 info->stack_size += SIZEOF_REGISTER;
997 g_assert (info->gr <= MIPS_LAST_ARG_REG);
999 ainfo->storage = ArgInIReg;
1000 ainfo->reg = info->gr;
1002 info->gr_passed = TRUE;
1007 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
1008 /* First, see if we need to drop onto the stack */
1009 if (!info->on_stack) {
1010 if (info->gr > MIPS_LAST_ARG_REG)
1011 args_onto_stack (info);
1012 else if (info->fr > MIPS_LAST_FPARG_REG)
1013 args_onto_stack (info);
1016 /* Now, place the argument */
1017 if (info->on_stack) {
1018 ainfo->storage = ArgOnStack;
1019 ainfo->reg = mips_sp; /* in the caller */
1020 ainfo->offset = info->stack_size;
1021 info->stack_size += FREG_SIZE;
1024 ainfo->storage = ArgInFReg;
1025 ainfo->reg = info->fr;
1027 /* FP and GP slots do not overlap */
1033 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1034 /* First, see if we need to drop onto the stack */
1035 if (!info->on_stack) {
1036 if (info->gr > MIPS_LAST_ARG_REG)
1037 args_onto_stack (info);
1038 else if (info->fr > MIPS_LAST_FPARG_REG)
1039 args_onto_stack (info);
1042 /* Now, place the argument */
1043 if (info->on_stack) {
1044 g_assert(info->stack_size % 4 == 0);
1045 info->stack_size += (info->stack_size % 8);
1047 ainfo->storage = ArgOnStack;
1048 ainfo->reg = mips_sp; /* in the caller */
1049 ainfo->offset = info->stack_size;
1050 info->stack_size += FREG_SIZE;
1053 ainfo->storage = ArgInFReg;
1054 ainfo->reg = info->fr;
1056 /* FP and GP slots do not overlap */
1063 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1066 int n = sig->hasthis + sig->param_count;
1068 MonoType* simpletype;
1070 gboolean is_pinvoke = sig->pinvoke;
1073 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1075 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1077 cinfo->fr = MIPS_FIRST_FPARG_REG;
1078 cinfo->gr = MIPS_FIRST_ARG_REG;
1079 cinfo->stack_size = 0;
1081 DEBUG(printf("calculate_sizes\n"));
1083 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1087 /* handle returning a struct */
1088 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1089 cinfo->struct_ret = cinfo->gr;
1090 add_int32_arg (cinfo, &cinfo->ret);
1094 add_int32_arg (cinfo, cinfo->args + n);
1099 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1100 * the first argument, allowing 'this' to be always passed in the first arg reg.
1101 * Also do this if the first argument is a reference type, since virtual calls
1102 * are sometimes made using calli without sig->hasthis set, like in the delegate
1105 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1107 add_int32_arg (cinfo, cinfo->args + n);
1110 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1114 add_int32_arg (cinfo, &cinfo->ret);
1115 cinfo->struct_ret = cinfo->ret.reg;
1119 add_int32_arg (cinfo, cinfo->args + n);
1123 if (cinfo->vtype_retaddr) {
1124 add_int32_arg (cinfo, &cinfo->ret);
1125 cinfo->struct_ret = cinfo->ret.reg;
1130 DEBUG(printf("params: %d\n", sig->param_count));
1131 for (i = pstart; i < sig->param_count; ++i) {
1132 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1133 /* Prevent implicit arguments and sig_cookie from
1134 being passed in registers */
1135 args_onto_stack (cinfo);
1136 /* Emit the signature cookie just before the implicit arguments */
1137 add_int32_arg (cinfo, &cinfo->sig_cookie);
1139 DEBUG(printf("param %d: ", i));
1140 simpletype = mini_get_underlying_type (sig->params [i]);
1141 switch (simpletype->type) {
1142 case MONO_TYPE_BOOLEAN:
1145 DEBUG(printf("1 byte\n"));
1146 cinfo->args [n].size = 1;
1147 add_int32_arg (cinfo, &cinfo->args[n]);
1150 case MONO_TYPE_CHAR:
1153 DEBUG(printf("2 bytes\n"));
1154 cinfo->args [n].size = 2;
1155 add_int32_arg (cinfo, &cinfo->args[n]);
1160 DEBUG(printf("4 bytes\n"));
1161 cinfo->args [n].size = 4;
1162 add_int32_arg (cinfo, &cinfo->args[n]);
1168 case MONO_TYPE_FNPTR:
1169 case MONO_TYPE_CLASS:
1170 case MONO_TYPE_OBJECT:
1171 case MONO_TYPE_STRING:
1172 case MONO_TYPE_SZARRAY:
1173 case MONO_TYPE_ARRAY:
1174 cinfo->args [n].size = sizeof (gpointer);
1175 add_int32_arg (cinfo, &cinfo->args[n]);
1178 case MONO_TYPE_GENERICINST:
1179 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1180 cinfo->args [n].size = sizeof (gpointer);
1181 add_int32_arg (cinfo, &cinfo->args[n]);
1186 case MONO_TYPE_TYPEDBYREF:
1187 case MONO_TYPE_VALUETYPE: {
1190 int has_offset = FALSE;
1192 gint size, alignment;
1195 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1196 size = sizeof (MonoTypedRef);
1197 alignment = sizeof (gpointer);
1199 klass = mono_class_from_mono_type (sig->params [i]);
1201 size = mono_class_native_size (klass, NULL);
1203 size = mono_class_value_size (klass, NULL);
1204 alignment = mono_class_min_align (klass);
1206 #if MIPS_PASS_STRUCTS_BY_VALUE
1207 /* Need to do alignment if struct contains long or double */
1208 if (alignment > 4) {
1209 /* Drop onto stack *before* looking at
1210 stack_size, if required. */
1211 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1212 args_onto_stack (cinfo);
1213 if (cinfo->stack_size & (alignment - 1)) {
1214 add_int32_arg (cinfo, &dummy_arg);
1216 g_assert (!(cinfo->stack_size & (alignment - 1)));
1220 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1221 mono_class_native_size (sig->params [i]->data.klass, NULL),
1222 cinfo->stack_size, alignment);
1224 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1225 g_assert (cinfo->args [n].size == 0);
1226 g_assert (cinfo->args [n].vtsize == 0);
1227 for (j = 0; j < nwords; ++j) {
1229 add_int32_arg (cinfo, &cinfo->args [n]);
1230 if (cinfo->on_stack)
1233 add_int32_arg (cinfo, &dummy_arg);
1234 if (!has_offset && cinfo->on_stack) {
1235 cinfo->args [n].offset = dummy_arg.offset;
1239 if (cinfo->on_stack)
1240 cinfo->args [n].vtsize += 1;
1242 cinfo->args [n].size += 1;
1244 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1245 cinfo->args [n].storage = ArgStructByVal;
1247 add_int32_arg (cinfo, &cinfo->args[n]);
1248 cinfo->args [n].storage = ArgStructByAddr;
1255 DEBUG(printf("8 bytes\n"));
1256 cinfo->args [n].size = 8;
1257 add_int64_arg (cinfo, &cinfo->args[n]);
1261 DEBUG(printf("R4\n"));
1262 cinfo->args [n].size = 4;
1263 add_float32_arg (cinfo, &cinfo->args[n]);
1267 DEBUG(printf("R8\n"));
1268 cinfo->args [n].size = 8;
1269 add_float64_arg (cinfo, &cinfo->args[n]);
1273 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1277 /* Handle the case where there are no implicit arguments */
1278 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1279 /* Prevent implicit arguments and sig_cookie from
1280 being passed in registers */
1281 args_onto_stack (cinfo);
1282 /* Emit the signature cookie just before the implicit arguments */
1283 add_int32_arg (cinfo, &cinfo->sig_cookie);
1287 simpletype = mini_get_underlying_type (sig->ret);
1288 switch (simpletype->type) {
1289 case MONO_TYPE_BOOLEAN:
1294 case MONO_TYPE_CHAR:
1300 case MONO_TYPE_FNPTR:
1301 case MONO_TYPE_CLASS:
1302 case MONO_TYPE_OBJECT:
1303 case MONO_TYPE_SZARRAY:
1304 case MONO_TYPE_ARRAY:
1305 case MONO_TYPE_STRING:
1306 cinfo->ret.reg = mips_v0;
1310 cinfo->ret.reg = mips_v0;
1314 cinfo->ret.reg = mips_f0;
1315 cinfo->ret.storage = ArgInFReg;
1317 case MONO_TYPE_GENERICINST:
1318 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1319 cinfo->ret.reg = mips_v0;
1323 case MONO_TYPE_VALUETYPE:
1324 case MONO_TYPE_TYPEDBYREF:
1326 case MONO_TYPE_VOID:
1329 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1333 /* align stack size to 16 */
1334 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1336 cinfo->stack_usage = cinfo->stack_size;
1341 debug_omit_fp (void)
1344 return mono_debug_count ();
1351 * mono_arch_compute_omit_fp:
1353 * Determine whenever the frame pointer can be eliminated.
1356 mono_arch_compute_omit_fp (MonoCompile *cfg)
1358 MonoMethodSignature *sig;
1359 MonoMethodHeader *header;
1363 if (cfg->arch.omit_fp_computed)
1366 header = cfg->header;
1368 sig = mono_method_signature (cfg->method);
1370 if (!cfg->arch.cinfo)
1371 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1372 cinfo = cfg->arch.cinfo;
1375 * FIXME: Remove some of the restrictions.
1377 cfg->arch.omit_fp = TRUE;
1378 cfg->arch.omit_fp_computed = TRUE;
1380 if (cfg->disable_omit_fp)
1381 cfg->arch.omit_fp = FALSE;
1382 if (!debug_omit_fp ())
1383 cfg->arch.omit_fp = FALSE;
1384 if (cfg->method->save_lmf)
1385 cfg->arch.omit_fp = FALSE;
1386 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1387 cfg->arch.omit_fp = FALSE;
1388 if (header->num_clauses)
1389 cfg->arch.omit_fp = FALSE;
1390 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1391 cfg->arch.omit_fp = FALSE;
1392 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1393 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1394 cfg->arch.omit_fp = FALSE;
1396 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1397 * there are stack arguments.
1400 if (cinfo->stack_usage)
1401 cfg->arch.omit_fp = FALSE;
1405 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1406 MonoInst *ins = cfg->varinfo [i];
1409 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1412 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1416 * Set var information according to the calling convention. mips version.
1417 * The locals var stuff should most likely be split in another method.
1420 mono_arch_allocate_vars (MonoCompile *cfg)
1422 MonoMethodSignature *sig;
1423 MonoMethodHeader *header;
1425 int i, offset, size, align, curinst;
1426 int frame_reg = mips_sp;
1427 guint32 iregs_to_save = 0;
1429 guint32 fregs_to_restore;
1433 sig = mono_method_signature (cfg->method);
1435 if (!cfg->arch.cinfo)
1436 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1437 cinfo = cfg->arch.cinfo;
1439 mono_arch_compute_omit_fp (cfg);
1441 /* spill down, we'll fix it in a separate pass */
1442 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1444 /* allow room for the vararg method args: void* and long/double */
1445 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1446 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1448 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1449 * call convs needs to be handled this way.
1451 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1452 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1454 /* gtk-sharp and other broken code will dllimport vararg functions even with
1455 * non-varargs signatures. Since there is little hope people will get this right
1456 * we assume they won't.
1458 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1459 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1461 /* a0-a3 always present */
1462 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1464 header = cfg->header;
1466 if (cfg->arch.omit_fp)
1467 frame_reg = mips_sp;
1469 frame_reg = mips_fp;
1470 cfg->frame_reg = frame_reg;
1471 if (frame_reg != mips_sp) {
1472 cfg->used_int_regs |= 1 << frame_reg;
1477 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1478 /* FIXME: handle long and FP values */
1479 switch (mini_get_underlying_type (sig->ret)->type) {
1480 case MONO_TYPE_VOID:
1484 cfg->ret->opcode = OP_REGVAR;
1485 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1488 cfg->ret->opcode = OP_REGVAR;
1489 cfg->ret->inst_c0 = mips_v0;
1493 /* Space for outgoing parameters, including a0-a3 */
1494 offset += cfg->param_area;
1496 /* allow room to save the return value (if it's a struct) */
1497 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1500 /* Now handle the local variables */
1502 curinst = cfg->locals_start;
1503 for (i = curinst; i < cfg->num_varinfo; ++i) {
1504 inst = cfg->varinfo [i];
1505 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1508 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1509 * pinvoke wrappers when they call functions returning structure
1511 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1512 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1514 size = mono_type_size (inst->inst_vtype, &align);
1516 offset += align - 1;
1517 offset &= ~(align - 1);
1518 inst->inst_offset = offset;
1519 inst->opcode = OP_REGOFFSET;
1520 inst->inst_basereg = frame_reg;
1522 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1525 /* Space for LMF (if needed) */
1526 if (cfg->method->save_lmf) {
1527 /* align the offset to 16 bytes */
1528 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1529 cfg->arch.lmf_offset = offset;
1530 offset += sizeof (MonoLMF);
1533 if (sig->call_convention == MONO_CALL_VARARG) {
1537 /* Allocate a local slot to hold the sig cookie address */
1538 offset += align - 1;
1539 offset &= ~(align - 1);
1540 cfg->sig_cookie = offset;
1544 offset += SIZEOF_REGISTER - 1;
1545 offset &= ~(SIZEOF_REGISTER - 1);
1547 /* Space for saved registers */
1548 cfg->arch.iregs_offset = offset;
1549 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1550 if (iregs_to_save) {
1551 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1552 if (iregs_to_save & (1 << i)) {
1553 offset += SIZEOF_REGISTER;
1558 /* saved float registers */
1560 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1561 if (fregs_to_restore) {
1562 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1563 if (fregs_to_restore & (1 << i)) {
1564 offset += sizeof(double);
1570 #if _MIPS_SIM == _ABIO32
1571 /* Now add space for saving the ra */
1572 offset += SIZEOF_VOID_P;
1575 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1576 cfg->stack_offset = offset;
1577 cfg->arch.local_alloc_offset = cfg->stack_offset;
1581 * Now allocate stack slots for the int arg regs (a0 - a3)
1582 * On MIPS o32, these are just above the incoming stack pointer
1583 * Even if the arg has been assigned to a regvar, it gets a stack slot
1586 /* Return struct-by-value results in a hidden first argument */
1587 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1588 cfg->vret_addr->opcode = OP_REGOFFSET;
1589 cfg->vret_addr->inst_c0 = mips_a0;
1590 cfg->vret_addr->inst_offset = offset;
1591 cfg->vret_addr->inst_basereg = frame_reg;
1592 offset += SIZEOF_REGISTER;
1595 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1596 inst = cfg->args [i];
1597 if (inst->opcode != OP_REGVAR) {
1600 if (sig->hasthis && (i == 0))
1601 arg_type = &mono_defaults.object_class->byval_arg;
1603 arg_type = sig->params [i - sig->hasthis];
1605 inst->opcode = OP_REGOFFSET;
1606 size = mono_type_size (arg_type, &align);
1608 if (size < SIZEOF_REGISTER) {
1609 size = SIZEOF_REGISTER;
1610 align = SIZEOF_REGISTER;
1612 inst->inst_basereg = frame_reg;
1613 offset = (offset + align - 1) & ~(align - 1);
1614 inst->inst_offset = offset;
1616 if (cfg->verbose_level > 1)
1617 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1620 #if _MIPS_SIM == _ABIO32
1621 /* o32: Even a0-a3 get stack slots */
1622 size = SIZEOF_REGISTER;
1623 align = SIZEOF_REGISTER;
1624 inst->inst_basereg = frame_reg;
1625 offset = (offset + align - 1) & ~(align - 1);
1626 inst->inst_offset = offset;
1628 if (cfg->verbose_level > 1)
1629 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1633 #if _MIPS_SIM == _ABIN32
1634 /* Now add space for saving the ra */
1635 offset += SIZEOF_VOID_P;
1638 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1639 cfg->stack_offset = offset;
1640 cfg->arch.local_alloc_offset = cfg->stack_offset;
1645 mono_arch_create_vars (MonoCompile *cfg)
1647 MonoMethodSignature *sig;
1649 sig = mono_method_signature (cfg->method);
1651 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1652 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1653 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1654 printf ("vret_addr = ");
1655 mono_print_ins (cfg->vret_addr);
1660 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1661 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1665 * take the arguments and generate the arch-specific
1666 * instructions to properly call the function in call.
1667 * This includes pushing, moving arguments to the right register
1669 * Issue: who does the spilling if needed, and when?
1672 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1674 MonoMethodSignature *tmp_sig;
1677 if (call->tail_call)
1680 /* FIXME: Add support for signature tokens to AOT */
1681 cfg->disable_aot = TRUE;
1684 * mono_ArgIterator_Setup assumes the signature cookie is
1685 * passed first and all the arguments which were before it are
1686 * passed on the stack after the signature. So compensate by
1687 * passing a different signature.
1689 tmp_sig = mono_metadata_signature_dup (call->signature);
1690 tmp_sig->param_count -= call->signature->sentinelpos;
1691 tmp_sig->sentinelpos = 0;
1692 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1694 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1695 sig_arg->dreg = mono_alloc_ireg (cfg);
1696 sig_arg->inst_p0 = tmp_sig;
1697 MONO_ADD_INS (cfg->cbb, sig_arg);
1699 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1703 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1706 MonoMethodSignature *sig;
1711 sig = call->signature;
1712 n = sig->param_count + sig->hasthis;
1714 cinfo = get_call_info (cfg->mempool, sig);
1715 if (cinfo->struct_ret)
1716 call->used_iregs |= 1 << cinfo->struct_ret;
1718 for (i = 0; i < n; ++i) {
1719 ArgInfo *ainfo = cinfo->args + i;
1722 if (i >= sig->hasthis)
1723 t = sig->params [i - sig->hasthis];
1725 t = &mono_defaults.int_class->byval_arg;
1726 t = mini_get_underlying_type (t);
1728 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1729 /* Emit the signature cookie just before the implicit arguments */
1730 emit_sig_cookie (cfg, call, cinfo);
1733 if (is_virtual && i == 0) {
1734 /* the argument will be attached to the call instrucion */
1735 in = call->args [i];
1736 call->used_iregs |= 1 << ainfo->reg;
1739 in = call->args [i];
1740 if (ainfo->storage == ArgInIReg) {
1741 #if SIZEOF_REGISTER == 4
1742 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1743 MONO_INST_NEW (cfg, ins, OP_MOVE);
1744 ins->dreg = mono_alloc_ireg (cfg);
1745 ins->sreg1 = in->dreg + 1;
1746 MONO_ADD_INS (cfg->cbb, ins);
1747 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1749 MONO_INST_NEW (cfg, ins, OP_MOVE);
1750 ins->dreg = mono_alloc_ireg (cfg);
1751 ins->sreg1 = in->dreg + 2;
1752 MONO_ADD_INS (cfg->cbb, ins);
1753 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1756 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1759 #if PROMOTE_R4_TO_R8
1760 /* ??? - convert to single first? */
1761 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1762 ins->dreg = mono_alloc_freg (cfg);
1763 ins->sreg1 = in->dreg;
1764 MONO_ADD_INS (cfg->cbb, ins);
1769 /* trying to load float value into int registers */
1770 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1771 ins->dreg = mono_alloc_ireg (cfg);
1773 MONO_ADD_INS (cfg->cbb, ins);
1774 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1775 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1776 /* trying to load float value into int registers */
1777 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1778 ins->dreg = mono_alloc_ireg (cfg);
1779 ins->sreg1 = in->dreg;
1780 MONO_ADD_INS (cfg->cbb, ins);
1781 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1783 MONO_INST_NEW (cfg, ins, OP_MOVE);
1784 ins->dreg = mono_alloc_ireg (cfg);
1785 ins->sreg1 = in->dreg;
1786 MONO_ADD_INS (cfg->cbb, ins);
1787 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1789 } else if (ainfo->storage == ArgStructByAddr) {
1790 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1791 ins->opcode = OP_OUTARG_VT;
1792 ins->sreg1 = in->dreg;
1793 ins->klass = in->klass;
1794 ins->inst_p0 = call;
1795 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1796 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1797 MONO_ADD_INS (cfg->cbb, ins);
1798 } else if (ainfo->storage == ArgStructByVal) {
1799 /* this is further handled in mono_arch_emit_outarg_vt () */
1800 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1801 ins->opcode = OP_OUTARG_VT;
1802 ins->sreg1 = in->dreg;
1803 ins->klass = in->klass;
1804 ins->inst_p0 = call;
1805 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1806 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1807 MONO_ADD_INS (cfg->cbb, ins);
1808 } else if (ainfo->storage == ArgOnStack) {
1809 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1810 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1811 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1812 if (t->type == MONO_TYPE_R8)
1813 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1815 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1817 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1819 } else if (ainfo->storage == ArgInFReg) {
1820 if (t->type == MONO_TYPE_VALUETYPE) {
1821 /* this is further handled in mono_arch_emit_outarg_vt () */
1822 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1823 ins->opcode = OP_OUTARG_VT;
1824 ins->sreg1 = in->dreg;
1825 ins->klass = in->klass;
1826 ins->inst_p0 = call;
1827 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1828 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1829 MONO_ADD_INS (cfg->cbb, ins);
1831 cfg->flags |= MONO_CFG_HAS_FPOUT;
1833 int dreg = mono_alloc_freg (cfg);
1835 if (ainfo->size == 4) {
1836 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1838 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1840 ins->sreg1 = in->dreg;
1841 MONO_ADD_INS (cfg->cbb, ins);
1844 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1845 cfg->flags |= MONO_CFG_HAS_FPOUT;
1848 g_assert_not_reached ();
1852 /* Handle the case where there are no implicit arguments */
1853 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1854 emit_sig_cookie (cfg, call, cinfo);
1856 if (cinfo->struct_ret) {
1859 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1860 vtarg->sreg1 = call->vret_var->dreg;
1861 vtarg->dreg = mono_alloc_preg (cfg);
1862 MONO_ADD_INS (cfg->cbb, vtarg);
1864 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1868 * Reverse the call->out_args list.
1871 MonoInst *prev = NULL, *list = call->out_args, *next;
1878 call->out_args = prev;
1881 call->stack_usage = cinfo->stack_usage;
1882 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1883 #if _MIPS_SIM == _ABIO32
1884 /* a0-a3 always present */
1885 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1887 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1888 cfg->flags |= MONO_CFG_HAS_CALLS;
1890 * should set more info in call, such as the stack space
1891 * used by the args that needs to be added back to esp
1896 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1898 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1899 ArgInfo *ainfo = ins->inst_p1;
1900 int ovf_size = ainfo->vtsize;
1901 int doffset = ainfo->offset;
1902 int i, soffset, dreg;
1904 if (ainfo->storage == ArgStructByVal) {
1906 if (cfg->verbose_level > 0) {
1907 char* nm = mono_method_full_name (cfg->method, TRUE);
1908 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1909 nm, doffset, ainfo->size, ovf_size);
1915 for (i = 0; i < ainfo->size; ++i) {
1916 dreg = mono_alloc_ireg (cfg);
1917 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1918 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1919 soffset += SIZEOF_REGISTER;
1921 if (ovf_size != 0) {
1922 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1924 } else if (ainfo->storage == ArgInFReg) {
1925 int tmpr = mono_alloc_freg (cfg);
1927 if (ainfo->size == 4)
1928 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1930 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1931 dreg = mono_alloc_freg (cfg);
1932 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1933 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1935 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1939 /* FIXME: alignment? */
1940 if (call->signature->pinvoke) {
1941 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1942 vtcopy->backend.is_pinvoke = 1;
1944 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1947 g_assert (ovf_size > 0);
1949 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1950 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1953 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1955 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1960 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1962 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1965 #if (SIZEOF_REGISTER == 4)
1966 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1969 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1970 ins->sreg1 = val->dreg + 1;
1971 ins->sreg2 = val->dreg + 2;
1972 MONO_ADD_INS (cfg->cbb, ins);
1976 if (ret->type == MONO_TYPE_R8) {
1977 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1980 if (ret->type == MONO_TYPE_R4) {
1981 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1985 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1989 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1991 MonoInst *ins, *n, *last_ins = NULL;
1993 if (cfg->verbose_level > 2)
1994 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1997 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1998 if (cfg->verbose_level > 2)
1999 mono_print_ins_index (0, ins);
2001 switch (ins->opcode) {
2003 case OP_LOAD_MEMBASE:
2004 case OP_LOADI4_MEMBASE:
2006 * OP_IADD reg2, reg1, const1
2007 * OP_LOAD_MEMBASE const2(reg2), reg3
2009 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
2011 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)){
2012 int const1 = last_ins->inst_imm;
2013 int const2 = ins->inst_offset;
2015 if (mips_is_imm16 (const1 + const2)) {
2016 ins->inst_basereg = last_ins->sreg1;
2017 ins->inst_offset = const1 + const2;
2027 bb->last_ins = last_ins;
2031 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2033 MonoInst *ins, *n, *last_ins = NULL;
2036 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2037 MonoInst *last_ins = ins->prev;
2039 switch (ins->opcode) {
2041 /* remove unnecessary multiplication with 1 */
2042 if (ins->inst_imm == 1) {
2043 if (ins->dreg != ins->sreg1) {
2044 ins->opcode = OP_MOVE;
2046 MONO_DELETE_INS (bb, ins);
2050 int power2 = mono_is_power_of_two (ins->inst_imm);
2052 ins->opcode = OP_SHL_IMM;
2053 ins->inst_imm = power2;
2057 case OP_LOAD_MEMBASE:
2058 case OP_LOADI4_MEMBASE:
2060 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2061 * OP_LOAD_MEMBASE offset(basereg), reg
2063 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2064 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2065 ins->inst_basereg == last_ins->inst_destbasereg &&
2066 ins->inst_offset == last_ins->inst_offset) {
2067 if (ins->dreg == last_ins->sreg1) {
2068 MONO_DELETE_INS (bb, ins);
2071 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2072 ins->opcode = OP_MOVE;
2073 ins->sreg1 = last_ins->sreg1;
2078 * Note: reg1 must be different from the basereg in the second load
2079 * OP_LOAD_MEMBASE offset(basereg), reg1
2080 * OP_LOAD_MEMBASE offset(basereg), reg2
2082 * OP_LOAD_MEMBASE offset(basereg), reg1
2083 * OP_MOVE reg1, reg2
2085 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2086 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2087 ins->inst_basereg != last_ins->dreg &&
2088 ins->inst_basereg == last_ins->inst_basereg &&
2089 ins->inst_offset == last_ins->inst_offset) {
2091 if (ins->dreg == last_ins->dreg) {
2092 MONO_DELETE_INS (bb, ins);
2095 ins->opcode = OP_MOVE;
2096 ins->sreg1 = last_ins->dreg;
2099 //g_assert_not_reached ();
2104 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2105 * OP_LOAD_MEMBASE offset(basereg), reg
2107 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2108 * OP_ICONST reg, imm
2110 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2111 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2112 ins->inst_basereg == last_ins->inst_destbasereg &&
2113 ins->inst_offset == last_ins->inst_offset) {
2114 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2115 ins->opcode = OP_ICONST;
2116 ins->inst_c0 = last_ins->inst_imm;
2117 g_assert_not_reached (); // check this rule
2122 case OP_LOADU1_MEMBASE:
2123 case OP_LOADI1_MEMBASE:
2124 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2125 ins->inst_basereg == last_ins->inst_destbasereg &&
2126 ins->inst_offset == last_ins->inst_offset) {
2127 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2128 ins->sreg1 = last_ins->sreg1;
2131 case OP_LOADU2_MEMBASE:
2132 case OP_LOADI2_MEMBASE:
2133 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2134 ins->inst_basereg == last_ins->inst_destbasereg &&
2135 ins->inst_offset == last_ins->inst_offset) {
2136 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2137 ins->sreg1 = last_ins->sreg1;
2140 case OP_ICONV_TO_I4:
2141 case OP_ICONV_TO_U4:
2143 ins->opcode = OP_MOVE;
2147 if (ins->dreg == ins->sreg1) {
2148 MONO_DELETE_INS (bb, ins);
2152 * OP_MOVE sreg, dreg
2153 * OP_MOVE dreg, sreg
2155 if (last_ins && last_ins->opcode == OP_MOVE &&
2156 ins->sreg1 == last_ins->dreg &&
2157 ins->dreg == last_ins->sreg1) {
2158 MONO_DELETE_INS (bb, ins);
2166 bb->last_ins = last_ins;
2170 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2178 switch (ins->opcode) {
2181 case OP_LCOMPARE_IMM:
2182 mono_print_ins (ins);
2183 g_assert_not_reached ();
2186 tmp1 = mono_alloc_ireg (cfg);
2187 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2188 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2189 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2190 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2195 tmp1 = mono_alloc_ireg (cfg);
2196 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2197 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2198 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2199 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2204 tmp1 = mono_alloc_ireg (cfg);
2205 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2206 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2207 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2208 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2213 tmp1 = mono_alloc_ireg (cfg);
2214 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2215 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2216 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2217 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2229 mono_print_ins (ins);
2230 g_assert_not_reached ();
2233 tmp1 = mono_alloc_ireg (cfg);
2234 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2235 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2236 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2237 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2245 case OP_LCONV_TO_I1:
2246 case OP_LCONV_TO_I2:
2247 case OP_LCONV_TO_I4:
2248 case OP_LCONV_TO_I8:
2249 case OP_LCONV_TO_R4:
2250 case OP_LCONV_TO_R8:
2251 case OP_LCONV_TO_U4:
2252 case OP_LCONV_TO_U8:
2253 case OP_LCONV_TO_U2:
2254 case OP_LCONV_TO_U1:
2256 case OP_LCONV_TO_OVF_I:
2257 case OP_LCONV_TO_OVF_U:
2259 mono_print_ins (ins);
2260 g_assert_not_reached ();
2263 tmp1 = mono_alloc_ireg (cfg);
2264 tmp2 = mono_alloc_ireg (cfg);
2265 tmp3 = mono_alloc_ireg (cfg);
2266 tmp4 = mono_alloc_ireg (cfg);
2267 tmp5 = mono_alloc_ireg (cfg);
2269 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2271 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2272 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2274 /* add the high 32-bits, and add in the carry from the low 32-bits */
2275 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2276 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2278 /* Overflow happens if
2279 * neg + neg = pos or
2281 * XOR of the high bits returns 0 if the signs match
2282 * XOR of that with the high bit of the result return 1 if overflow.
2285 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2286 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2288 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2289 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2290 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2292 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2293 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2294 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2296 /* Now, if (tmp4 == 0) then overflow */
2297 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2301 case OP_LADD_OVF_UN:
2302 tmp1 = mono_alloc_ireg (cfg);
2303 tmp2 = mono_alloc_ireg (cfg);
2305 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2306 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2307 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2308 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2309 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2310 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2315 case OP_LMUL_OVF_UN:
2316 mono_print_ins (ins);
2317 g_assert_not_reached ();
2320 tmp1 = mono_alloc_ireg (cfg);
2321 tmp2 = mono_alloc_ireg (cfg);
2322 tmp3 = mono_alloc_ireg (cfg);
2323 tmp4 = mono_alloc_ireg (cfg);
2324 tmp5 = mono_alloc_ireg (cfg);
2326 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2328 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2329 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2330 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2332 /* Overflow happens if
2333 * neg - pos = pos or
2335 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2337 * tmp1 = (lhs ^ rhs)
2338 * tmp2 = (lhs ^ result)
2339 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2342 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2343 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2344 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2345 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2347 /* Now, if (tmp4 == 1) then overflow */
2348 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2352 case OP_LSUB_OVF_UN:
2353 tmp1 = mono_alloc_ireg (cfg);
2354 tmp2 = mono_alloc_ireg (cfg);
2356 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2357 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2358 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2359 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2361 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2362 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2366 case OP_LCONV_TO_OVF_I1_UN:
2367 case OP_LCONV_TO_OVF_I2_UN:
2368 case OP_LCONV_TO_OVF_I4_UN:
2369 case OP_LCONV_TO_OVF_I8_UN:
2370 case OP_LCONV_TO_OVF_U1_UN:
2371 case OP_LCONV_TO_OVF_U2_UN:
2372 case OP_LCONV_TO_OVF_U4_UN:
2373 case OP_LCONV_TO_OVF_U8_UN:
2374 case OP_LCONV_TO_OVF_I_UN:
2375 case OP_LCONV_TO_OVF_U_UN:
2376 case OP_LCONV_TO_OVF_I1:
2377 case OP_LCONV_TO_OVF_U1:
2378 case OP_LCONV_TO_OVF_I2:
2379 case OP_LCONV_TO_OVF_U2:
2380 case OP_LCONV_TO_OVF_I4:
2381 case OP_LCONV_TO_OVF_U4:
2382 case OP_LCONV_TO_OVF_I8:
2383 case OP_LCONV_TO_OVF_U8:
2391 case OP_LCONV_TO_R_UN:
2397 case OP_LSHR_UN_IMM:
2399 case OP_LDIV_UN_IMM:
2401 case OP_LREM_UN_IMM:
2412 mono_print_ins (ins);
2413 g_assert_not_reached ();
2415 case OP_LCONV_TO_R8_2:
2416 case OP_LCONV_TO_R4_2:
2417 case OP_LCONV_TO_R_UN_2:
2419 case OP_LCONV_TO_OVF_I4_2:
2420 tmp1 = mono_alloc_ireg (cfg);
2422 /* Overflows if reg2 != sign extension of reg1 */
2423 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2424 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2425 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2433 mono_print_ins (ins);
2434 g_assert_not_reached ();
2442 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2450 switch (ins->opcode) {
2452 tmp1 = mono_alloc_ireg (cfg);
2453 tmp2 = mono_alloc_ireg (cfg);
2454 tmp3 = mono_alloc_ireg (cfg);
2455 tmp4 = mono_alloc_ireg (cfg);
2456 tmp5 = mono_alloc_ireg (cfg);
2458 /* add the operands */
2460 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2462 /* Overflow happens if
2463 * neg + neg = pos or
2466 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2467 * XOR of the high bit returns 0 if the signs match
2468 * XOR of that with the high bit of the result return 1 if overflow.
2471 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2472 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2474 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2475 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2476 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2478 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2479 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2481 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2483 /* Now, if (tmp5 == 0) then overflow */
2484 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2485 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2486 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2490 case OP_IADD_OVF_UN:
2491 tmp1 = mono_alloc_ireg (cfg);
2493 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2494 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2495 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2496 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2497 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2502 tmp1 = mono_alloc_ireg (cfg);
2503 tmp2 = mono_alloc_ireg (cfg);
2504 tmp3 = mono_alloc_ireg (cfg);
2505 tmp4 = mono_alloc_ireg (cfg);
2506 tmp5 = mono_alloc_ireg (cfg);
2508 /* add the operands */
2510 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2512 /* Overflow happens if
2513 * neg - pos = pos or
2515 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2517 * tmp1 = (lhs ^ rhs)
2518 * tmp2 = (lhs ^ result)
2519 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2522 /* tmp3 = 1 if the signs of the two inputs differ */
2523 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2524 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2525 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2526 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2527 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2529 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2530 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2531 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2535 case OP_ISUB_OVF_UN:
2536 tmp1 = mono_alloc_ireg (cfg);
2538 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2539 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2540 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2541 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2542 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2549 map_to_reg_reg_op (int op)
2558 case OP_COMPARE_IMM:
2560 case OP_ICOMPARE_IMM:
2562 case OP_LCOMPARE_IMM:
2578 case OP_LOAD_MEMBASE:
2579 return OP_LOAD_MEMINDEX;
2580 case OP_LOADI4_MEMBASE:
2581 return OP_LOADI4_MEMINDEX;
2582 case OP_LOADU4_MEMBASE:
2583 return OP_LOADU4_MEMINDEX;
2584 case OP_LOADU1_MEMBASE:
2585 return OP_LOADU1_MEMINDEX;
2586 case OP_LOADI2_MEMBASE:
2587 return OP_LOADI2_MEMINDEX;
2588 case OP_LOADU2_MEMBASE:
2589 return OP_LOADU2_MEMINDEX;
2590 case OP_LOADI1_MEMBASE:
2591 return OP_LOADI1_MEMINDEX;
2592 case OP_LOADR4_MEMBASE:
2593 return OP_LOADR4_MEMINDEX;
2594 case OP_LOADR8_MEMBASE:
2595 return OP_LOADR8_MEMINDEX;
2596 case OP_STOREI1_MEMBASE_REG:
2597 return OP_STOREI1_MEMINDEX;
2598 case OP_STOREI2_MEMBASE_REG:
2599 return OP_STOREI2_MEMINDEX;
2600 case OP_STOREI4_MEMBASE_REG:
2601 return OP_STOREI4_MEMINDEX;
2602 case OP_STORE_MEMBASE_REG:
2603 return OP_STORE_MEMINDEX;
2604 case OP_STORER4_MEMBASE_REG:
2605 return OP_STORER4_MEMINDEX;
2606 case OP_STORER8_MEMBASE_REG:
2607 return OP_STORER8_MEMINDEX;
2608 case OP_STORE_MEMBASE_IMM:
2609 return OP_STORE_MEMBASE_REG;
2610 case OP_STOREI1_MEMBASE_IMM:
2611 return OP_STOREI1_MEMBASE_REG;
2612 case OP_STOREI2_MEMBASE_IMM:
2613 return OP_STOREI2_MEMBASE_REG;
2614 case OP_STOREI4_MEMBASE_IMM:
2615 return OP_STOREI4_MEMBASE_REG;
2616 case OP_STOREI8_MEMBASE_IMM:
2617 return OP_STOREI8_MEMBASE_REG;
2619 return mono_op_imm_to_op (op);
2623 map_to_mips_op (int op)
2627 return OP_MIPS_FBEQ;
2629 return OP_MIPS_FBGE;
2631 return OP_MIPS_FBGT;
2633 return OP_MIPS_FBLE;
2635 return OP_MIPS_FBLT;
2637 return OP_MIPS_FBNE;
2639 return OP_MIPS_FBGE_UN;
2641 return OP_MIPS_FBGT_UN;
2643 return OP_MIPS_FBLE_UN;
2645 return OP_MIPS_FBLT_UN;
2653 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2654 g_assert_not_reached ();
2658 #define NEW_INS(cfg,after,dest,op) do { \
2659 MONO_INST_NEW((cfg), (dest), (op)); \
2660 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2663 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2665 MONO_INST_NEW(cfg, temp, (op)); \
2666 mono_bblock_insert_after_ins (bb, (pos), temp); \
2667 temp->dreg = (_dreg); \
2668 temp->sreg1 = (_sreg1); \
2669 temp->sreg2 = (_sreg2); \
2673 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2675 MONO_INST_NEW(cfg, temp, (op)); \
2676 mono_bblock_insert_after_ins (bb, (pos), temp); \
2677 temp->dreg = (_dreg); \
2678 temp->sreg1 = (_sreg1); \
2679 temp->inst_c0 = (_imm); \
2684 * Remove from the instruction list the instructions that can't be
2685 * represented with very simple instructions with no register
2689 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2691 MonoInst *ins, *next, *temp, *last_ins = NULL;
2695 if (cfg->verbose_level > 2) {
2698 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2699 MONO_BB_FOR_EACH_INS (bb, ins) {
2700 mono_print_ins_index (idx++, ins);
2706 MONO_BB_FOR_EACH_INS (bb, ins) {
2708 switch (ins->opcode) {
2713 /* Branch opts can eliminate the branch */
2714 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2720 case OP_COMPARE_IMM:
2721 case OP_ICOMPARE_IMM:
2722 case OP_LCOMPARE_IMM:
2724 /* Branch opts can eliminate the branch */
2725 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2729 if (ins->inst_imm) {
2730 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2731 temp->inst_c0 = ins->inst_imm;
2732 temp->dreg = mono_alloc_ireg (cfg);
2733 ins->sreg2 = temp->dreg;
2737 ins->sreg2 = mips_zero;
2739 if (ins->opcode == OP_COMPARE_IMM)
2740 ins->opcode = OP_COMPARE;
2741 else if (ins->opcode == OP_ICOMPARE_IMM)
2742 ins->opcode = OP_ICOMPARE;
2743 else if (ins->opcode == OP_LCOMPARE_IMM)
2744 ins->opcode = OP_LCOMPARE;
2747 case OP_IDIV_UN_IMM:
2750 case OP_IREM_UN_IMM:
2751 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2752 temp->inst_c0 = ins->inst_imm;
2753 temp->dreg = mono_alloc_ireg (cfg);
2754 ins->sreg2 = temp->dreg;
2755 if (ins->opcode == OP_IDIV_IMM)
2756 ins->opcode = OP_IDIV;
2757 else if (ins->opcode == OP_IREM_IMM)
2758 ins->opcode = OP_IREM;
2759 else if (ins->opcode == OP_IDIV_UN_IMM)
2760 ins->opcode = OP_IDIV_UN;
2761 else if (ins->opcode == OP_IREM_UN_IMM)
2762 ins->opcode = OP_IREM_UN;
2764 /* handle rem separately */
2771 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2772 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2773 temp->inst_c0 = ins->inst_imm;
2774 temp->dreg = mono_alloc_ireg (cfg);
2775 ins->sreg2 = temp->dreg;
2776 ins->opcode = map_to_reg_reg_op (ins->opcode);
2786 /* unsigned 16 bit immediate */
2787 if (ins->inst_imm & 0xffff0000) {
2788 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2789 temp->inst_c0 = ins->inst_imm;
2790 temp->dreg = mono_alloc_ireg (cfg);
2791 ins->sreg2 = temp->dreg;
2792 ins->opcode = map_to_reg_reg_op (ins->opcode);
2799 /* signed 16 bit immediate */
2800 if (!mips_is_imm16 (ins->inst_imm)) {
2801 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2802 temp->inst_c0 = ins->inst_imm;
2803 temp->dreg = mono_alloc_ireg (cfg);
2804 ins->sreg2 = temp->dreg;
2805 ins->opcode = map_to_reg_reg_op (ins->opcode);
2811 if (!mips_is_imm16 (-ins->inst_imm)) {
2812 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2813 temp->inst_c0 = ins->inst_imm;
2814 temp->dreg = mono_alloc_ireg (cfg);
2815 ins->sreg2 = temp->dreg;
2816 ins->opcode = map_to_reg_reg_op (ins->opcode);
2822 if (ins->inst_imm == 1) {
2823 ins->opcode = OP_MOVE;
2826 if (ins->inst_imm == 0) {
2827 ins->opcode = OP_ICONST;
2831 imm = mono_is_power_of_two (ins->inst_imm);
2833 ins->opcode = OP_SHL_IMM;
2834 ins->inst_imm = imm;
2837 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2838 temp->inst_c0 = ins->inst_imm;
2839 temp->dreg = mono_alloc_ireg (cfg);
2840 ins->sreg2 = temp->dreg;
2841 ins->opcode = map_to_reg_reg_op (ins->opcode);
2844 case OP_LOCALLOC_IMM:
2845 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2846 temp->inst_c0 = ins->inst_imm;
2847 temp->dreg = mono_alloc_ireg (cfg);
2848 ins->sreg1 = temp->dreg;
2849 ins->opcode = OP_LOCALLOC;
2852 case OP_LOADR4_MEMBASE:
2853 case OP_STORER4_MEMBASE_REG:
2854 /* we can do two things: load the immed in a register
2855 * and use an indexed load, or see if the immed can be
2856 * represented as an ad_imm + a load with a smaller offset
2857 * that fits. We just do the first for now, optimize later.
2859 if (mips_is_imm16 (ins->inst_offset))
2861 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2862 temp->inst_c0 = ins->inst_offset;
2863 temp->dreg = mono_alloc_ireg (cfg);
2864 ins->sreg2 = temp->dreg;
2865 ins->opcode = map_to_reg_reg_op (ins->opcode);
2868 case OP_STORE_MEMBASE_IMM:
2869 case OP_STOREI1_MEMBASE_IMM:
2870 case OP_STOREI2_MEMBASE_IMM:
2871 case OP_STOREI4_MEMBASE_IMM:
2872 case OP_STOREI8_MEMBASE_IMM:
2873 if (!ins->inst_imm) {
2874 ins->sreg1 = mips_zero;
2875 ins->opcode = map_to_reg_reg_op (ins->opcode);
2878 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2879 temp->inst_c0 = ins->inst_imm;
2880 temp->dreg = mono_alloc_ireg (cfg);
2881 ins->sreg1 = temp->dreg;
2882 ins->opcode = map_to_reg_reg_op (ins->opcode);
2884 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2890 /* Branch opts can eliminate the branch */
2891 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2898 * remap compare/branch and compare/set
2899 * to MIPS specific opcodes.
2901 next->opcode = map_to_mips_op (next->opcode);
2902 next->sreg1 = ins->sreg1;
2903 next->sreg2 = ins->sreg2;
2910 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2911 temp->inst_c0 = (guint32)ins->inst_p0;
2912 temp->dreg = mono_alloc_ireg (cfg);
2913 ins->inst_basereg = temp->dreg;
2914 ins->inst_offset = 0;
2915 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2917 /* make it handle the possibly big ins->inst_offset
2918 * later optimize to use lis + load_membase
2923 g_assert (ins_is_compare(last_ins));
2924 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2925 NULLIFY_INS(last_ins);
2929 g_assert (ins_is_compare(last_ins));
2930 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2931 NULLIFY_INS(last_ins);
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_BEQ, 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_BEQ, last_ins->dreg, mips_zero);
2949 g_assert (ins_is_compare(last_ins));
2950 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2951 last_ins->dreg = mono_alloc_ireg (cfg);
2952 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2956 g_assert (ins_is_compare(last_ins));
2957 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2958 last_ins->dreg = mono_alloc_ireg (cfg);
2959 INS_REWRITE(ins, OP_MIPS_BNE, 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_BEQ, 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_BEQ, last_ins->dreg, mips_zero);
2977 g_assert (ins_is_compare(last_ins));
2978 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2979 last_ins->dreg = mono_alloc_ireg (cfg);
2980 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2984 g_assert (ins_is_compare(last_ins));
2985 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2986 last_ins->dreg = mono_alloc_ireg (cfg);
2987 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2992 g_assert (ins_is_compare(last_ins));
2993 last_ins->opcode = OP_IXOR;
2994 last_ins->dreg = mono_alloc_ireg(cfg);
2995 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
3000 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
3001 NULLIFY_INS(last_ins);
3007 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
3008 NULLIFY_INS(last_ins);
3013 g_assert (ins_is_compare(last_ins));
3014 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
3015 MONO_DELETE_INS(bb, last_ins);
3020 g_assert (ins_is_compare(last_ins));
3021 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
3022 MONO_DELETE_INS(bb, last_ins);
3025 case OP_COND_EXC_EQ:
3026 case OP_COND_EXC_IEQ:
3027 g_assert (ins_is_compare(last_ins));
3028 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
3029 MONO_DELETE_INS(bb, last_ins);
3032 case OP_COND_EXC_GE:
3033 case OP_COND_EXC_IGE:
3034 g_assert (ins_is_compare(last_ins));
3035 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
3036 MONO_DELETE_INS(bb, last_ins);
3039 case OP_COND_EXC_GT:
3040 case OP_COND_EXC_IGT:
3041 g_assert (ins_is_compare(last_ins));
3042 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
3043 MONO_DELETE_INS(bb, last_ins);
3046 case OP_COND_EXC_LE:
3047 case OP_COND_EXC_ILE:
3048 g_assert (ins_is_compare(last_ins));
3049 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
3050 MONO_DELETE_INS(bb, last_ins);
3053 case OP_COND_EXC_LT:
3054 case OP_COND_EXC_ILT:
3055 g_assert (ins_is_compare(last_ins));
3056 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
3057 MONO_DELETE_INS(bb, last_ins);
3060 case OP_COND_EXC_NE_UN:
3061 case OP_COND_EXC_INE_UN:
3062 g_assert (ins_is_compare(last_ins));
3063 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
3064 MONO_DELETE_INS(bb, last_ins);
3067 case OP_COND_EXC_GE_UN:
3068 case OP_COND_EXC_IGE_UN:
3069 g_assert (ins_is_compare(last_ins));
3070 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
3071 MONO_DELETE_INS(bb, last_ins);
3074 case OP_COND_EXC_GT_UN:
3075 case OP_COND_EXC_IGT_UN:
3076 g_assert (ins_is_compare(last_ins));
3077 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
3078 MONO_DELETE_INS(bb, last_ins);
3081 case OP_COND_EXC_LE_UN:
3082 case OP_COND_EXC_ILE_UN:
3083 g_assert (ins_is_compare(last_ins));
3084 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
3085 MONO_DELETE_INS(bb, last_ins);
3088 case OP_COND_EXC_LT_UN:
3089 case OP_COND_EXC_ILT_UN:
3090 g_assert (ins_is_compare(last_ins));
3091 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
3092 MONO_DELETE_INS(bb, last_ins);
3095 case OP_COND_EXC_OV:
3096 case OP_COND_EXC_IOV: {
3097 int tmp1, tmp2, tmp3, tmp4, tmp5;
3098 MonoInst *pos = last_ins;
3100 /* Overflow happens if
3101 * neg + neg = pos or
3104 * (bit31s of operands match) AND (bit31 of operand
3105 * != bit31 of result)
3106 * XOR of the high bit returns 0 if the signs match
3107 * XOR of that with the high bit of the result return 1
3110 g_assert (last_ins->opcode == OP_IADC);
3112 tmp1 = mono_alloc_ireg (cfg);
3113 tmp2 = mono_alloc_ireg (cfg);
3114 tmp3 = mono_alloc_ireg (cfg);
3115 tmp4 = mono_alloc_ireg (cfg);
3116 tmp5 = mono_alloc_ireg (cfg);
3118 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3119 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
3121 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3122 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
3123 INS (pos, OP_INOT, tmp3, tmp2, -1);
3125 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3126 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
3127 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3129 /* Now, if (tmp5 == 0) then overflow */
3130 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3135 case OP_COND_EXC_NO:
3136 case OP_COND_EXC_INO:
3137 g_assert_not_reached ();
3141 case OP_COND_EXC_IC:
3142 g_assert_not_reached ();
3145 case OP_COND_EXC_NC:
3146 case OP_COND_EXC_INC:
3147 g_assert_not_reached ();
3153 bb->last_ins = last_ins;
3154 bb->max_vreg = cfg->next_vreg;
3157 if (cfg->verbose_level > 2) {
3160 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3161 MONO_BB_FOR_EACH_INS (bb, ins) {
3162 mono_print_ins_index (idx++, ins);
3171 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3173 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3175 mips_truncwd (code, mips_ftemp, sreg);
3177 mips_cvtwd (code, mips_ftemp, sreg);
3179 mips_mfc1 (code, dreg, mips_ftemp);
3182 mips_andi (code, dreg, dreg, 0xff);
3183 else if (size == 2) {
3184 mips_sll (code, dreg, dreg, 16);
3185 mips_srl (code, dreg, dreg, 16);
3189 mips_sll (code, dreg, dreg, 24);
3190 mips_sra (code, dreg, dreg, 24);
3192 else if (size == 2) {
3193 mips_sll (code, dreg, dreg, 16);
3194 mips_sra (code, dreg, dreg, 16);
3201 * emit_load_volatile_arguments:
3203 * Load volatile arguments from the stack to the original input registers.
3204 * Required before a tail call.
3207 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3209 MonoMethod *method = cfg->method;
3210 MonoMethodSignature *sig;
3215 sig = mono_method_signature (method);
3217 if (!cfg->arch.cinfo)
3218 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3219 cinfo = cfg->arch.cinfo;
3221 if (cinfo->struct_ret) {
3222 ArgInfo *ainfo = &cinfo->ret;
3223 inst = cfg->vret_addr;
3224 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3227 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3228 ArgInfo *ainfo = cinfo->args + i;
3229 inst = cfg->args [i];
3230 if (inst->opcode == OP_REGVAR) {
3231 if (ainfo->storage == ArgInIReg)
3232 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3233 else if (ainfo->storage == ArgInFReg)
3234 g_assert_not_reached();
3235 else if (ainfo->storage == ArgOnStack) {
3238 g_assert_not_reached ();
3240 if (ainfo->storage == ArgInIReg) {
3241 g_assert (mips_is_imm16 (inst->inst_offset));
3242 switch (ainfo->size) {
3244 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3247 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3251 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3254 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3255 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3258 g_assert_not_reached ();
3261 } else if (ainfo->storage == ArgOnStack) {
3263 } else if (ainfo->storage == ArgInFReg) {
3264 g_assert (mips_is_imm16 (inst->inst_offset));
3265 if (ainfo->size == 8) {
3266 #if _MIPS_SIM == _ABIO32
3267 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3268 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3269 #elif _MIPS_SIM == _ABIN32
3270 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3273 else if (ainfo->size == 4)
3274 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3276 g_assert_not_reached ();
3277 } else if (ainfo->storage == ArgStructByVal) {
3279 int doffset = inst->inst_offset;
3281 g_assert (mips_is_imm16 (inst->inst_offset));
3282 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3283 for (i = 0; i < ainfo->size; ++i) {
3284 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3285 doffset += SIZEOF_REGISTER;
3287 } else if (ainfo->storage == ArgStructByAddr) {
3288 g_assert (mips_is_imm16 (inst->inst_offset));
3289 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3291 g_assert_not_reached ();
3299 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3301 int size = cfg->param_area;
3303 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3304 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3309 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3310 if (ppc_is_imm16 (-size)) {
3311 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3313 ppc_load (code, ppc_r12, -size);
3314 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3321 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3323 int size = cfg->param_area;
3325 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3326 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3331 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3332 if (ppc_is_imm16 (size)) {
3333 ppc_stwu (code, ppc_r0, size, ppc_sp);
3335 ppc_load (code, ppc_r12, size);
3336 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3343 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3348 guint8 *code = cfg->native_code + cfg->code_len;
3349 MonoInst *last_ins = NULL;
3350 guint last_offset = 0;
3354 /* we don't align basic blocks of loops on mips */
3356 if (cfg->verbose_level > 2)
3357 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3359 cpos = bb->max_offset;
3362 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3363 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3364 g_assert (!mono_compile_aot);
3367 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3368 /* this is not thread save, but good enough */
3369 /* fixme: howto handle overflows? */
3370 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3371 mips_lw (code, mips_temp, mips_at, 0);
3372 mips_addiu (code, mips_temp, mips_temp, 1);
3373 mips_sw (code, mips_temp, mips_at, 0);
3376 MONO_BB_FOR_EACH_INS (bb, ins) {
3377 offset = code - cfg->native_code;
3379 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3381 if (offset > (cfg->code_size - max_len - 16)) {
3382 cfg->code_size *= 2;
3383 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3384 code = cfg->native_code + offset;
3386 mono_debug_record_line_number (cfg, ins, offset);
3387 if (cfg->verbose_level > 2) {
3388 g_print (" @ 0x%x\t", offset);
3389 mono_print_ins_index (ins_cnt++, ins);
3391 /* Check for virtual regs that snuck by */
3392 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3394 switch (ins->opcode) {
3395 case OP_RELAXED_NOP:
3398 case OP_DUMMY_STORE:
3399 case OP_NOT_REACHED:
3402 case OP_IL_SEQ_POINT:
3403 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3405 case OP_SEQ_POINT: {
3406 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3407 guint32 addr = (guint32)ss_trigger_page;
3409 mips_load_const (code, mips_t9, addr);
3410 mips_lw (code, mips_t9, mips_t9, 0);
3413 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3416 * A placeholder for a possible breakpoint inserted by
3417 * mono_arch_set_breakpoint ().
3419 /* mips_load_const () + mips_lw */
3426 g_assert_not_reached();
3428 emit_tls_access (code, ins->dreg, ins->inst_offset);
3432 mips_mult (code, ins->sreg1, ins->sreg2);
3433 mips_mflo (code, ins->dreg);
3434 mips_mfhi (code, ins->dreg+1);
3437 mips_multu (code, ins->sreg1, ins->sreg2);
3438 mips_mflo (code, ins->dreg);
3439 mips_mfhi (code, ins->dreg+1);
3441 case OP_MEMORY_BARRIER:
3442 mips_sync (code, 0);
3444 case OP_STOREI1_MEMBASE_IMM:
3445 mips_load_const (code, mips_temp, ins->inst_imm);
3446 if (mips_is_imm16 (ins->inst_offset)) {
3447 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3449 mips_load_const (code, mips_at, ins->inst_offset);
3450 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3453 case OP_STOREI2_MEMBASE_IMM:
3454 mips_load_const (code, mips_temp, ins->inst_imm);
3455 if (mips_is_imm16 (ins->inst_offset)) {
3456 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3458 mips_load_const (code, mips_at, ins->inst_offset);
3459 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3462 case OP_STOREI8_MEMBASE_IMM:
3463 mips_load_const (code, mips_temp, ins->inst_imm);
3464 if (mips_is_imm16 (ins->inst_offset)) {
3465 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3467 mips_load_const (code, mips_at, ins->inst_offset);
3468 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3471 case OP_STORE_MEMBASE_IMM:
3472 case OP_STOREI4_MEMBASE_IMM:
3473 mips_load_const (code, mips_temp, ins->inst_imm);
3474 if (mips_is_imm16 (ins->inst_offset)) {
3475 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3477 mips_load_const (code, mips_at, ins->inst_offset);
3478 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3481 case OP_STOREI1_MEMBASE_REG:
3482 if (mips_is_imm16 (ins->inst_offset)) {
3483 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3485 mips_load_const (code, mips_at, ins->inst_offset);
3486 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3487 mips_sb (code, ins->sreg1, mips_at, 0);
3490 case OP_STOREI2_MEMBASE_REG:
3491 if (mips_is_imm16 (ins->inst_offset)) {
3492 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3494 mips_load_const (code, mips_at, ins->inst_offset);
3495 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3496 mips_sh (code, ins->sreg1, mips_at, 0);
3499 case OP_STORE_MEMBASE_REG:
3500 case OP_STOREI4_MEMBASE_REG:
3501 if (mips_is_imm16 (ins->inst_offset)) {
3502 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3504 mips_load_const (code, mips_at, ins->inst_offset);
3505 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3506 mips_sw (code, ins->sreg1, mips_at, 0);
3509 case OP_STOREI8_MEMBASE_REG:
3510 if (mips_is_imm16 (ins->inst_offset)) {
3511 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3513 mips_load_const (code, mips_at, ins->inst_offset);
3514 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3515 mips_sd (code, ins->sreg1, mips_at, 0);
3519 g_assert_not_reached ();
3520 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3521 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3523 case OP_LOADI8_MEMBASE:
3524 if (mips_is_imm16 (ins->inst_offset)) {
3525 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3527 mips_load_const (code, mips_at, ins->inst_offset);
3528 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3529 mips_ld (code, ins->dreg, mips_at, 0);
3532 case OP_LOAD_MEMBASE:
3533 case OP_LOADI4_MEMBASE:
3534 case OP_LOADU4_MEMBASE:
3535 g_assert (ins->dreg != -1);
3536 if (mips_is_imm16 (ins->inst_offset)) {
3537 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3539 mips_load_const (code, mips_at, ins->inst_offset);
3540 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3541 mips_lw (code, ins->dreg, mips_at, 0);
3544 case OP_LOADI1_MEMBASE:
3545 if (mips_is_imm16 (ins->inst_offset)) {
3546 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3548 mips_load_const (code, mips_at, ins->inst_offset);
3549 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3550 mips_lb (code, ins->dreg, mips_at, 0);
3553 case OP_LOADU1_MEMBASE:
3554 if (mips_is_imm16 (ins->inst_offset)) {
3555 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3557 mips_load_const (code, mips_at, ins->inst_offset);
3558 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3559 mips_lbu (code, ins->dreg, mips_at, 0);
3562 case OP_LOADI2_MEMBASE:
3563 if (mips_is_imm16 (ins->inst_offset)) {
3564 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3566 mips_load_const (code, mips_at, ins->inst_offset);
3567 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3568 mips_lh (code, ins->dreg, mips_at, 0);
3571 case OP_LOADU2_MEMBASE:
3572 if (mips_is_imm16 (ins->inst_offset)) {
3573 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3575 mips_load_const (code, mips_at, ins->inst_offset);
3576 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3577 mips_lhu (code, ins->dreg, mips_at, 0);
3580 case OP_ICONV_TO_I1:
3581 mips_sll (code, mips_at, ins->sreg1, 24);
3582 mips_sra (code, ins->dreg, mips_at, 24);
3584 case OP_ICONV_TO_I2:
3585 mips_sll (code, mips_at, ins->sreg1, 16);
3586 mips_sra (code, ins->dreg, mips_at, 16);
3588 case OP_ICONV_TO_U1:
3589 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3591 case OP_ICONV_TO_U2:
3592 mips_sll (code, mips_at, ins->sreg1, 16);
3593 mips_srl (code, ins->dreg, mips_at, 16);
3596 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3599 g_assert (mips_is_imm16 (ins->inst_imm));
3600 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3603 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3606 g_assert (mips_is_imm16 (ins->inst_imm));
3607 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3611 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3612 * So instead of emitting a trap, we emit a call a C function and place a
3615 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3616 (gpointer)"mono_break");
3617 mips_load (code, mips_t9, 0x1f1f1f1f);
3618 mips_jalr (code, mips_t9, mips_ra);
3622 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3625 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3630 g_assert (mips_is_imm16 (ins->inst_imm));
3631 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3634 g_assert (mips_is_imm16 (ins->inst_imm));
3635 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3639 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3642 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3647 // we add the negated value
3648 g_assert (mips_is_imm16 (-ins->inst_imm));
3649 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3653 // we add the negated value
3654 g_assert (mips_is_imm16 (-ins->inst_imm));
3655 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3660 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3666 g_assert (!(ins->inst_imm & 0xffff0000));
3667 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3672 guint32 *divisor_is_m1;
3673 guint32 *dividend_is_minvalue;
3674 guint32 *divisor_is_zero;
3676 mips_load_const (code, mips_at, -1);
3677 divisor_is_m1 = (guint32 *)(void *)code;
3678 mips_bne (code, ins->sreg2, mips_at, 0);
3679 mips_lui (code, mips_at, mips_zero, 0x8000);
3680 dividend_is_minvalue = (guint32 *)(void *)code;
3681 mips_bne (code, ins->sreg1, mips_at, 0);
3684 /* Divide Int32.MinValue by -1 -- throw exception */
3685 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3687 mips_patch (divisor_is_m1, (guint32)code);
3688 mips_patch (dividend_is_minvalue, (guint32)code);
3690 /* Put divide in branch delay slot (NOT YET) */
3691 divisor_is_zero = (guint32 *)(void *)code;
3692 mips_bne (code, ins->sreg2, mips_zero, 0);
3695 /* Divide by zero -- throw exception */
3696 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3698 mips_patch (divisor_is_zero, (guint32)code);
3699 mips_div (code, ins->sreg1, ins->sreg2);
3700 if (ins->opcode == OP_IDIV)
3701 mips_mflo (code, ins->dreg);
3703 mips_mfhi (code, ins->dreg);
3708 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3710 /* Put divide in branch delay slot (NOT YET) */
3711 mips_bne (code, ins->sreg2, mips_zero, 0);
3714 /* Divide by zero -- throw exception */
3715 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3717 mips_patch (divisor_is_zero, (guint32)code);
3718 mips_divu (code, ins->sreg1, ins->sreg2);
3719 if (ins->opcode == OP_IDIV_UN)
3720 mips_mflo (code, ins->dreg);
3722 mips_mfhi (code, ins->dreg);
3726 g_assert_not_reached ();
3728 ppc_load (code, ppc_r12, ins->inst_imm);
3729 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3730 ppc_mfspr (code, ppc_r0, ppc_xer);
3731 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3732 /* FIXME: use OverflowException for 0x80000000/-1 */
3733 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3735 g_assert_not_reached();
3738 g_assert_not_reached ();
3740 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3744 g_assert (!(ins->inst_imm & 0xffff0000));
3745 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3748 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3752 /* unsigned 16-bit immediate */
3753 g_assert (!(ins->inst_imm & 0xffff0000));
3754 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3757 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3761 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3764 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3767 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3771 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3774 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3777 case OP_ISHR_UN_IMM:
3778 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3780 case OP_LSHR_UN_IMM:
3781 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3784 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3787 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3791 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3794 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3797 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3801 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3803 mips_mult (code, ins->sreg1, ins->sreg2);
3804 mips_mflo (code, ins->dreg);
3809 #if SIZEOF_REGISTER == 8
3811 mips_dmult (code, ins->sreg1, ins->sreg2);
3812 mips_mflo (code, ins->dreg);
3817 mips_mult (code, ins->sreg1, ins->sreg2);
3818 mips_mflo (code, ins->dreg);
3819 mips_mfhi (code, mips_at);
3822 mips_sra (code, mips_temp, ins->dreg, 31);
3823 patch = (guint32 *)(void *)code;
3824 mips_beq (code, mips_temp, mips_at, 0);
3826 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3827 mips_patch (patch, (guint32)code);
3830 case OP_IMUL_OVF_UN: {
3832 mips_mult (code, ins->sreg1, ins->sreg2);
3833 mips_mflo (code, ins->dreg);
3834 mips_mfhi (code, mips_at);
3837 patch = (guint32 *)(void *)code;
3838 mips_beq (code, mips_at, mips_zero, 0);
3840 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3841 mips_patch (patch, (guint32)code);
3845 mips_load_const (code, ins->dreg, ins->inst_c0);
3847 #if SIZEOF_REGISTER == 8
3849 mips_load_const (code, ins->dreg, ins->inst_c0);
3853 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3854 mips_load (code, ins->dreg, 0);
3858 mips_mtc1 (code, ins->dreg, ins->sreg1);
3860 case OP_MIPS_MTC1S_2:
3861 mips_mtc1 (code, ins->dreg, ins->sreg1);
3862 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3865 mips_mfc1 (code, ins->dreg, ins->sreg1);
3868 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3872 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3874 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3875 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3879 case OP_ICONV_TO_I4:
3880 case OP_ICONV_TO_U4:
3882 if (ins->dreg != ins->sreg1)
3883 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3885 #if SIZEOF_REGISTER == 8
3887 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3888 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3891 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3892 mips_dsra (code, ins->dreg, ins->dreg, 32);
3896 int lsreg = mips_v0 + ls_word_idx;
3897 int msreg = mips_v0 + ms_word_idx;
3899 /* Get sreg1 into lsreg, sreg2 into msreg */
3901 if (ins->sreg1 == msreg) {
3902 if (ins->sreg1 != mips_at)
3903 MIPS_MOVE (code, mips_at, ins->sreg1);
3904 if (ins->sreg2 != msreg)
3905 MIPS_MOVE (code, msreg, ins->sreg2);
3906 MIPS_MOVE (code, lsreg, mips_at);
3909 if (ins->sreg2 != msreg)
3910 MIPS_MOVE (code, msreg, ins->sreg2);
3911 if (ins->sreg1 != lsreg)
3912 MIPS_MOVE (code, lsreg, ins->sreg1);
3917 if (ins->dreg != ins->sreg1) {
3918 mips_fmovd (code, ins->dreg, ins->sreg1);
3921 case OP_MOVE_F_TO_I4:
3922 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3923 mips_mfc1 (code, ins->dreg, mips_ftemp);
3925 case OP_MOVE_I4_TO_F:
3926 mips_mtc1 (code, ins->dreg, ins->sreg1);
3927 mips_cvtds (code, ins->dreg, ins->dreg);
3930 /* Convert from double to float and leave it there */
3931 mips_cvtsd (code, ins->dreg, ins->sreg1);
3933 case OP_FCONV_TO_R4:
3935 mips_cvtsd (code, ins->dreg, ins->sreg1);
3937 /* Just a move, no precision change */
3938 if (ins->dreg != ins->sreg1) {
3939 mips_fmovd (code, ins->dreg, ins->sreg1);
3944 code = emit_load_volatile_arguments(cfg, code);
3947 * Pop our stack, then jump to specified method (tail-call)
3948 * Keep in sync with mono_arch_emit_epilog
3950 code = mono_arch_emit_epilog_sub (cfg, code);
3952 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3953 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3954 mips_load (code, mips_t9, 0);
3955 mips_jr (code, mips_t9);
3959 /* ensure ins->sreg1 is not NULL */
3960 mips_lw (code, mips_zero, ins->sreg1, 0);
3963 g_assert (mips_is_imm16 (cfg->sig_cookie));
3964 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3965 mips_sw (code, mips_at, ins->sreg1, 0);
3978 case OP_VOIDCALL_REG:
3980 case OP_FCALL_MEMBASE:
3981 case OP_LCALL_MEMBASE:
3982 case OP_VCALL_MEMBASE:
3983 case OP_VCALL2_MEMBASE:
3984 case OP_VOIDCALL_MEMBASE:
3985 case OP_CALL_MEMBASE:
3986 call = (MonoCallInst*)ins;
3987 switch (ins->opcode) {
3994 if (ins->flags & MONO_INST_HAS_METHOD) {
3995 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3996 mips_load (code, mips_t9, call->method);
3999 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4000 mips_load (code, mips_t9, call->fptr);
4002 mips_jalr (code, mips_t9, mips_ra);
4009 case OP_VOIDCALL_REG:
4011 MIPS_MOVE (code, mips_t9, ins->sreg1);
4012 mips_jalr (code, mips_t9, mips_ra);
4015 case OP_FCALL_MEMBASE:
4016 case OP_LCALL_MEMBASE:
4017 case OP_VCALL_MEMBASE:
4018 case OP_VCALL2_MEMBASE:
4019 case OP_VOIDCALL_MEMBASE:
4020 case OP_CALL_MEMBASE:
4021 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
4022 mips_jalr (code, mips_t9, mips_ra);
4026 #if PROMOTE_R4_TO_R8
4027 /* returned an FP R4 (single), promote to R8 (double) in place */
4028 switch (ins->opcode) {
4031 case OP_FCALL_MEMBASE:
4032 if (call->signature->ret->type == MONO_TYPE_R4)
4033 mips_cvtds (code, mips_f0, mips_f0);
4041 int area_offset = cfg->param_area;
4043 /* Round up ins->sreg1, mips_at ends up holding size */
4044 mips_addiu (code, mips_at, ins->sreg1, 31);
4045 mips_addiu (code, mips_temp, mips_zero, ~31);
4046 mips_and (code, mips_at, mips_at, mips_temp);
4048 mips_subu (code, mips_sp, mips_sp, mips_at);
4049 g_assert (mips_is_imm16 (area_offset));
4050 mips_addiu (code, ins->dreg, mips_sp, area_offset);
4052 if (ins->flags & MONO_INST_INIT) {
4055 buf = (guint32*)(void*)code;
4056 mips_beq (code, mips_at, mips_zero, 0);
4059 mips_move (code, mips_temp, ins->dreg);
4060 mips_sb (code, mips_zero, mips_temp, 0);
4061 mips_addiu (code, mips_at, mips_at, -1);
4062 mips_bne (code, mips_at, mips_zero, -3);
4063 mips_addiu (code, mips_temp, mips_temp, 1);
4065 mips_patch (buf, (guint32)code);
4070 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
4071 mips_move (code, mips_a0, ins->sreg1);
4072 mips_call (code, mips_t9, addr);
4073 mips_break (code, 0xfc);
4077 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
4078 mips_move (code, mips_a0, ins->sreg1);
4079 mips_call (code, mips_t9, addr);
4080 mips_break (code, 0xfb);
4083 case OP_START_HANDLER: {
4085 * The START_HANDLER instruction marks the beginning of
4086 * a handler block. It is called using a call
4087 * instruction, so mips_ra contains the return address.
4088 * Since the handler executes in the same stack frame
4089 * as the method itself, we can't use save/restore to
4090 * save the return address. Instead, we save it into
4091 * a dedicated variable.
4093 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4094 g_assert (spvar->inst_basereg != mips_sp);
4095 code = emit_reserve_param_area (cfg, code);
4097 if (mips_is_imm16 (spvar->inst_offset)) {
4098 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4100 mips_load_const (code, mips_at, spvar->inst_offset);
4101 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4102 mips_sw (code, mips_ra, mips_at, 0);
4106 case OP_ENDFILTER: {
4107 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4108 g_assert (spvar->inst_basereg != mips_sp);
4109 code = emit_unreserve_param_area (cfg, code);
4111 if (ins->sreg1 != mips_v0)
4112 MIPS_MOVE (code, mips_v0, ins->sreg1);
4113 if (mips_is_imm16 (spvar->inst_offset)) {
4114 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4116 mips_load_const (code, mips_at, spvar->inst_offset);
4117 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4118 mips_lw (code, mips_ra, mips_at, 0);
4120 mips_jr (code, mips_ra);
4124 case OP_ENDFINALLY: {
4125 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4126 g_assert (spvar->inst_basereg != mips_sp);
4127 code = emit_unreserve_param_area (cfg, code);
4128 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
4129 mips_jalr (code, mips_t9, mips_ra);
4133 case OP_CALL_HANDLER:
4134 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4135 mips_lui (code, mips_t9, mips_zero, 0);
4136 mips_addiu (code, mips_t9, mips_t9, 0);
4137 mips_jalr (code, mips_t9, mips_ra);
4139 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4140 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4143 ins->inst_c0 = code - cfg->native_code;
4146 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4147 if (cfg->arch.long_branch) {
4148 mips_lui (code, mips_at, mips_zero, 0);
4149 mips_addiu (code, mips_at, mips_at, 0);
4150 mips_jr (code, mips_at);
4154 mips_beq (code, mips_zero, mips_zero, 0);
4159 mips_jr (code, ins->sreg1);
4165 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4166 if (offset > (cfg->code_size - max_len - 16)) {
4167 cfg->code_size += max_len;
4168 cfg->code_size *= 2;
4169 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4170 code = cfg->native_code + offset;
4172 g_assert (ins->sreg1 != -1);
4173 mips_sll (code, mips_at, ins->sreg1, 2);
4174 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4175 MIPS_MOVE (code, mips_t8, mips_ra);
4176 mips_bgezal (code, mips_zero, 1); /* bal */
4178 mips_addu (code, mips_t9, mips_ra, mips_at);
4179 /* Table is 16 or 20 bytes from target of bal above */
4180 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4181 MIPS_MOVE (code, mips_ra, mips_t8);
4182 mips_lw (code, mips_t9, mips_t9, 20);
4185 mips_lw (code, mips_t9, mips_t9, 16);
4186 mips_jalr (code, mips_t9, mips_t8);
4188 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4189 mips_emit32 (code, 0xfefefefe);
4194 mips_addiu (code, ins->dreg, mips_zero, 1);
4195 mips_beq (code, mips_at, mips_zero, 2);
4197 MIPS_MOVE (code, ins->dreg, mips_zero);
4203 mips_addiu (code, ins->dreg, mips_zero, 1);
4204 mips_bltz (code, mips_at, 2);
4206 MIPS_MOVE (code, ins->dreg, mips_zero);
4212 mips_addiu (code, ins->dreg, mips_zero, 1);
4213 mips_bgtz (code, mips_at, 2);
4215 MIPS_MOVE (code, ins->dreg, mips_zero);
4218 case OP_MIPS_COND_EXC_EQ:
4219 case OP_MIPS_COND_EXC_GE:
4220 case OP_MIPS_COND_EXC_GT:
4221 case OP_MIPS_COND_EXC_LE:
4222 case OP_MIPS_COND_EXC_LT:
4223 case OP_MIPS_COND_EXC_NE_UN:
4224 case OP_MIPS_COND_EXC_GE_UN:
4225 case OP_MIPS_COND_EXC_GT_UN:
4226 case OP_MIPS_COND_EXC_LE_UN:
4227 case OP_MIPS_COND_EXC_LT_UN:
4229 case OP_MIPS_COND_EXC_OV:
4230 case OP_MIPS_COND_EXC_NO:
4231 case OP_MIPS_COND_EXC_C:
4232 case OP_MIPS_COND_EXC_NC:
4234 case OP_MIPS_COND_EXC_IEQ:
4235 case OP_MIPS_COND_EXC_IGE:
4236 case OP_MIPS_COND_EXC_IGT:
4237 case OP_MIPS_COND_EXC_ILE:
4238 case OP_MIPS_COND_EXC_ILT:
4239 case OP_MIPS_COND_EXC_INE_UN:
4240 case OP_MIPS_COND_EXC_IGE_UN:
4241 case OP_MIPS_COND_EXC_IGT_UN:
4242 case OP_MIPS_COND_EXC_ILE_UN:
4243 case OP_MIPS_COND_EXC_ILT_UN:
4245 case OP_MIPS_COND_EXC_IOV:
4246 case OP_MIPS_COND_EXC_INO:
4247 case OP_MIPS_COND_EXC_IC:
4248 case OP_MIPS_COND_EXC_INC: {
4252 /* If the condition is true, raise the exception */
4254 /* need to reverse test to skip around exception raising */
4256 /* For the moment, branch around a branch to avoid reversing
4259 /* Remember, an unpatched branch to 0 branches to the delay slot */
4260 switch (ins->opcode) {
4261 case OP_MIPS_COND_EXC_EQ:
4262 throw = (guint32 *)(void *)code;
4263 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4267 case OP_MIPS_COND_EXC_NE_UN:
4268 throw = (guint32 *)(void *)code;
4269 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4273 case OP_MIPS_COND_EXC_LE_UN:
4274 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4275 throw = (guint32 *)(void *)code;
4276 mips_beq (code, mips_at, mips_zero, 0);
4280 case OP_MIPS_COND_EXC_GT:
4281 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4282 throw = (guint32 *)(void *)code;
4283 mips_bne (code, mips_at, mips_zero, 0);
4287 case OP_MIPS_COND_EXC_GT_UN:
4288 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4289 throw = (guint32 *)(void *)code;
4290 mips_bne (code, mips_at, mips_zero, 0);
4294 case OP_MIPS_COND_EXC_LT:
4295 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4296 throw = (guint32 *)(void *)code;
4297 mips_bne (code, mips_at, mips_zero, 0);
4301 case OP_MIPS_COND_EXC_LT_UN:
4302 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4303 throw = (guint32 *)(void *)code;
4304 mips_bne (code, mips_at, mips_zero, 0);
4309 /* Not yet implemented */
4310 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4311 g_assert_not_reached ();
4313 skip = (guint32 *)(void *)code;
4314 mips_beq (code, mips_zero, mips_zero, 0);
4316 mips_patch (throw, (guint32)code);
4317 code = mips_emit_exc_by_name (code, ins->inst_p1);
4318 mips_patch (skip, (guint32)code);
4319 cfg->bb_exit->max_offset += 24;
4328 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4331 /* floating point opcodes */
4334 if (((guint32)ins->inst_p0) & (1 << 15))
4335 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4337 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4338 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4340 mips_load_const (code, mips_at, ins->inst_p0);
4341 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4342 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4346 if (((guint32)ins->inst_p0) & (1 << 15))
4347 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4349 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4350 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4351 #if PROMOTE_R4_TO_R8
4352 mips_cvtds (code, ins->dreg, ins->dreg);
4355 case OP_STORER8_MEMBASE_REG:
4356 if (mips_is_imm16 (ins->inst_offset)) {
4357 #if _MIPS_SIM == _ABIO32
4358 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4359 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4360 #elif _MIPS_SIM == _ABIN32
4361 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4364 mips_load_const (code, mips_at, ins->inst_offset);
4365 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4366 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4367 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4370 case OP_LOADR8_MEMBASE:
4371 if (mips_is_imm16 (ins->inst_offset)) {
4372 #if _MIPS_SIM == _ABIO32
4373 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4374 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4375 #elif _MIPS_SIM == _ABIN32
4376 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4379 mips_load_const (code, mips_at, ins->inst_offset);
4380 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4381 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4382 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4385 case OP_STORER4_MEMBASE_REG:
4386 g_assert (mips_is_imm16 (ins->inst_offset));
4387 #if PROMOTE_R4_TO_R8
4388 /* Need to convert ins->sreg1 to single-precision first */
4389 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4390 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4392 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4396 g_assert (mips_is_imm16 (ins->inst_offset));
4397 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4399 case OP_LOADR4_MEMBASE:
4400 g_assert (mips_is_imm16 (ins->inst_offset));
4401 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4402 #if PROMOTE_R4_TO_R8
4403 /* Convert to double precision in place */
4404 mips_cvtds (code, ins->dreg, ins->dreg);
4407 case OP_LOADR4_MEMINDEX:
4408 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4409 mips_lwc1 (code, ins->dreg, mips_at, 0);
4411 case OP_LOADR8_MEMINDEX:
4412 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4413 #if _MIPS_SIM == _ABIO32
4414 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4415 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4416 #elif _MIPS_SIM == _ABIN32
4417 mips_ldc1 (code, ins->dreg, mips_at, 0);
4420 case OP_STORER4_MEMINDEX:
4421 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4422 #if PROMOTE_R4_TO_R8
4423 /* Need to convert ins->sreg1 to single-precision first */
4424 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4425 mips_swc1 (code, mips_ftemp, mips_at, 0);
4427 mips_swc1 (code, ins->sreg1, mips_at, 0);
4430 case OP_STORER8_MEMINDEX:
4431 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4432 #if _MIPS_SIM == _ABIO32
4433 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4434 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4435 #elif _MIPS_SIM == _ABIN32
4436 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4439 case OP_ICONV_TO_R_UN: {
4440 static const guint64 adjust_val = 0x41F0000000000000ULL;
4442 /* convert unsigned int to double */
4443 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4444 mips_bgez (code, ins->sreg1, 5);
4445 mips_cvtdw (code, ins->dreg, mips_ftemp);
4447 mips_load (code, mips_at, (guint32) &adjust_val);
4448 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4449 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4450 /* target is here */
4453 case OP_ICONV_TO_R4:
4454 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4455 mips_cvtsw (code, ins->dreg, mips_ftemp);
4456 mips_cvtds (code, ins->dreg, ins->dreg);
4458 case OP_ICONV_TO_R8:
4459 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4460 mips_cvtdw (code, ins->dreg, mips_ftemp);
4462 case OP_FCONV_TO_I1:
4463 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4465 case OP_FCONV_TO_U1:
4466 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4468 case OP_FCONV_TO_I2:
4469 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4471 case OP_FCONV_TO_U2:
4472 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4474 case OP_FCONV_TO_I4:
4476 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4478 case OP_FCONV_TO_U4:
4480 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4483 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4486 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4489 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4492 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4495 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4498 mips_fnegd (code, ins->dreg, ins->sreg1);
4501 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4502 mips_addiu (code, ins->dreg, mips_zero, 1);
4503 mips_fbtrue (code, 2);
4505 MIPS_MOVE (code, ins->dreg, mips_zero);
4508 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4509 mips_addiu (code, ins->dreg, mips_zero, 1);
4510 mips_fbtrue (code, 2);
4512 MIPS_MOVE (code, ins->dreg, mips_zero);
4515 /* Less than, or Unordered */
4516 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4517 mips_addiu (code, ins->dreg, mips_zero, 1);
4518 mips_fbtrue (code, 2);
4520 MIPS_MOVE (code, ins->dreg, mips_zero);
4523 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4524 MIPS_MOVE (code, ins->dreg, mips_zero);
4525 mips_fbtrue (code, 2);
4527 mips_addiu (code, ins->dreg, mips_zero, 1);
4530 /* Greater than, or Unordered */
4531 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4532 MIPS_MOVE (code, ins->dreg, mips_zero);
4533 mips_fbtrue (code, 2);
4535 mips_addiu (code, ins->dreg, mips_zero, 1);
4540 case OP_MIPS_FBLT_UN:
4542 case OP_MIPS_FBGT_UN:
4544 case OP_MIPS_FBGE_UN:
4546 case OP_MIPS_FBLE_UN: {
4548 gboolean is_true = TRUE, is_ordered = FALSE;
4549 guint32 *buf = NULL;
4551 switch (ins->opcode) {
4565 case OP_MIPS_FBLT_UN:
4566 cond = MIPS_FPU_ULT;
4574 case OP_MIPS_FBGT_UN:
4575 cond = MIPS_FPU_OLE;
4583 case OP_MIPS_FBGE_UN:
4584 cond = MIPS_FPU_OLT;
4588 cond = MIPS_FPU_OLE;
4592 case OP_MIPS_FBLE_UN:
4593 cond = MIPS_FPU_ULE;
4597 g_assert_not_reached ();
4601 /* Skip the check if unordered */
4602 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4604 buf = (guint32*)code;
4605 mips_fbtrue (code, 0);
4609 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4611 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4613 mips_fbtrue (code, 0);
4615 mips_fbfalse (code, 0);
4619 mips_patch (buf, (guint32)code);
4623 guint32 *branch_patch;
4625 mips_mfc1 (code, mips_at, ins->sreg1+1);
4626 mips_srl (code, mips_at, mips_at, 16+4);
4627 mips_andi (code, mips_at, mips_at, 2047);
4628 mips_addiu (code, mips_at, mips_at, -2047);
4630 branch_patch = (guint32 *)(void *)code;
4631 mips_bne (code, mips_at, mips_zero, 0);
4634 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4635 mips_patch (branch_patch, (guint32)code);
4636 mips_fmovd (code, ins->dreg, ins->sreg1);
4640 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4641 mips_load (code, ins->dreg, 0x0f0f0f0f);
4643 case OP_GC_SAFE_POINT:
4648 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4649 g_assert_not_reached ();
4652 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4653 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4654 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4655 g_assert_not_reached ();
4661 last_offset = offset;
4664 cfg->code_len = code - cfg->native_code;
4668 mono_arch_register_lowlevel_calls (void)
4673 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4675 MonoJumpInfo *patch_info;
4677 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4678 unsigned char *ip = patch_info->ip.i + code;
4679 const unsigned char *target = NULL;
4681 switch (patch_info->type) {
4682 case MONO_PATCH_INFO_IP:
4683 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4685 case MONO_PATCH_INFO_SWITCH: {
4686 gpointer *table = (gpointer *)patch_info->data.table->table;
4689 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4691 for (i = 0; i < patch_info->data.table->table_size; i++) {
4692 table [i] = (int)patch_info->data.table->table [i] + code;
4696 case MONO_PATCH_INFO_METHODCONST:
4697 case MONO_PATCH_INFO_CLASS:
4698 case MONO_PATCH_INFO_IMAGE:
4699 case MONO_PATCH_INFO_FIELD:
4700 case MONO_PATCH_INFO_VTABLE:
4701 case MONO_PATCH_INFO_IID:
4702 case MONO_PATCH_INFO_SFLDA:
4703 case MONO_PATCH_INFO_LDSTR:
4704 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4705 case MONO_PATCH_INFO_LDTOKEN:
4706 case MONO_PATCH_INFO_R4:
4707 case MONO_PATCH_INFO_R8:
4708 /* from OP_AOTCONST : lui + addiu */
4709 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4710 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4713 case MONO_PATCH_INFO_EXC_NAME:
4714 g_assert_not_reached ();
4715 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4718 case MONO_PATCH_INFO_NONE:
4719 /* everything is dealt with at epilog output time */
4722 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4723 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4730 * Allow tracing to work with this interface (with an optional argument)
4732 * This code is expected to be inserted just after the 'real' prolog code,
4733 * and before the first basic block. We need to allocate a 2nd, temporary
4734 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4738 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4741 int offset = cfg->arch.tracing_offset;
4747 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4748 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4749 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4750 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4751 #if _MIPS_SIM == _ABIN32
4753 /* FIXME: Need a separate region for these */
4754 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4755 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4756 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4757 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4761 mips_load_const (code, mips_a0, cfg->method);
4762 mips_addiu (code, mips_a1, mips_sp, offset);
4763 mips_call (code, mips_t9, func);
4766 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4767 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4768 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4769 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4770 #if _MIPS_SIM == _ABIN32
4773 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4774 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4775 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4776 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4787 mips_adjust_stackframe(MonoCompile *cfg)
4790 int delta, threshold, i;
4791 MonoMethodSignature *sig;
4794 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4797 /* adjust cfg->stack_offset for account for down-spilling */
4798 cfg->stack_offset += SIZEOF_REGISTER;
4800 /* re-align cfg->stack_offset if needed (due to var spilling) */
4801 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4802 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4803 if (cfg->verbose_level > 2) {
4804 g_print ("mips_adjust_stackframe:\n");
4805 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4807 threshold = cfg->arch.local_alloc_offset;
4808 ra_offset = cfg->stack_offset - sizeof(gpointer);
4809 if (cfg->verbose_level > 2) {
4810 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4813 sig = mono_method_signature (cfg->method);
4814 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4815 cfg->vret_addr->inst_offset += delta;
4817 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4818 MonoInst *inst = cfg->args [i];
4820 inst->inst_offset += delta;
4824 * loads and stores based off the frame reg that (used to) lie
4825 * above the spill var area need to be increased by 'delta'
4826 * to make room for the spill vars.
4828 /* Need to find loads and stores to adjust that
4829 * are above where the spillvars were inserted, but
4830 * which are not the spillvar references themselves.
4832 * Idea - since all offsets from fp are positive, make
4833 * spillvar offsets negative to begin with so we can spot
4838 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4842 if (cfg->verbose_level > 2) {
4843 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4845 MONO_BB_FOR_EACH_INS (bb, ins) {
4849 if (cfg->verbose_level > 2) {
4850 mono_print_ins_index (ins_cnt, ins);
4852 /* The == mips_sp tests catch FP spills */
4853 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4854 (ins->inst_basereg == mips_sp))) {
4855 switch (ins->opcode) {
4856 case OP_LOADI8_MEMBASE:
4857 case OP_LOADR8_MEMBASE:
4864 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4865 (ins->dreg == mips_sp))) {
4866 switch (ins->opcode) {
4867 case OP_STOREI8_MEMBASE_REG:
4868 case OP_STORER8_MEMBASE_REG:
4869 case OP_STOREI8_MEMBASE_IMM:
4877 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4880 if (ins->inst_c0 >= threshold) {
4881 ins->inst_c0 += delta;
4882 if (cfg->verbose_level > 2) {
4884 mono_print_ins_index (ins_cnt, ins);
4887 else if (ins->inst_c0 < 0) {
4888 /* Adj_c0 holds the size of the datatype. */
4889 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4890 if (cfg->verbose_level > 2) {
4892 mono_print_ins_index (ins_cnt, ins);
4895 g_assert (ins->inst_c0 != ra_offset);
4898 if (ins->inst_imm >= threshold) {
4899 ins->inst_imm += delta;
4900 if (cfg->verbose_level > 2) {
4902 mono_print_ins_index (ins_cnt, ins);
4905 g_assert (ins->inst_c0 != ra_offset);
4915 * Stack frame layout:
4917 * ------------------- sp + cfg->stack_usage + cfg->param_area
4918 * param area incoming
4919 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4921 * ------------------- sp + cfg->stack_usage
4923 * ------------------- sp + cfg->stack_usage-4
4925 * ------------------- sp +
4926 * MonoLMF structure optional
4927 * ------------------- sp + cfg->arch.lmf_offset
4928 * saved registers s0-s8
4929 * ------------------- sp + cfg->arch.iregs_offset
4931 * ------------------- sp + cfg->param_area
4932 * param area outgoing
4933 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4935 * ------------------- sp
4939 mono_arch_emit_prolog (MonoCompile *cfg)
4941 MonoMethod *method = cfg->method;
4942 MonoMethodSignature *sig;
4944 int alloc_size, pos, i, max_offset;
4945 int alloc2_size = 0;
4949 guint32 iregs_to_save = 0;
4951 guint32 fregs_to_save = 0;
4953 /* lmf_offset is the offset of the LMF from our stack pointer. */
4954 guint32 lmf_offset = cfg->arch.lmf_offset;
4958 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4962 cfg->flags |= MONO_CFG_HAS_CALLS;
4964 sig = mono_method_signature (method);
4965 cfg->code_size = 768 + sig->param_count * 20;
4966 code = cfg->native_code = g_malloc (cfg->code_size);
4969 * compute max_offset in order to use short forward jumps.
4972 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4973 MonoInst *ins = bb->code;
4974 bb->max_offset = max_offset;
4976 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4979 MONO_BB_FOR_EACH_INS (bb, ins)
4980 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4982 if (max_offset > 0xffff)
4983 cfg->arch.long_branch = TRUE;
4986 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4987 * This means that we have to adjust the offsets inside instructions which reference
4988 * arguments received on the stack, since the initial offset doesn't take into
4989 * account spill slots.
4991 mips_adjust_stackframe (cfg);
4993 /* Offset between current sp and the CFA */
4995 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4997 /* stack_offset should not be changed here. */
4998 alloc_size = cfg->stack_offset;
4999 cfg->stack_usage = alloc_size;
5001 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5004 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5006 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
5007 fregs_to_save |= (fregs_to_save << 1);
5010 /* If the stack size is too big, save 1024 bytes to start with
5011 * so the prologue can use imm16(reg) addressing, then allocate
5012 * the rest of the frame.
5014 if (alloc_size > ((1 << 15) - 1024)) {
5015 alloc2_size = alloc_size - 1024;
5019 g_assert (mips_is_imm16 (-alloc_size));
5020 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
5021 cfa_offset = alloc_size;
5022 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5025 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5026 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5027 if (mips_is_imm16(offset))
5028 mips_sw (code, mips_ra, mips_sp, offset);
5030 g_assert_not_reached ();
5032 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5033 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5036 /* XXX - optimize this later to not save all regs if LMF constructed */
5037 pos = cfg->arch.iregs_offset - alloc2_size;
5039 if (iregs_to_save) {
5040 /* save used registers in own stack frame (at pos) */
5041 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5042 if (iregs_to_save & (1 << i)) {
5043 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5044 g_assert (mips_is_imm16(pos));
5045 MIPS_SW (code, i, mips_sp, pos);
5046 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5047 pos += SIZEOF_REGISTER;
5052 // FIXME: Don't save registers twice if there is an LMF
5053 // s8 has to be special cased since it is overwritten with the updated value
5055 if (method->save_lmf) {
5056 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5057 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5058 g_assert (mips_is_imm16(offset));
5059 if (MIPS_LMF_IREGMASK & (1 << i))
5060 MIPS_SW (code, i, mips_sp, offset);
5065 /* Save float registers */
5066 if (fregs_to_save) {
5067 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5068 if (fregs_to_save & (1 << i)) {
5069 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5070 g_assert (mips_is_imm16(pos));
5071 mips_swc1 (code, i, mips_sp, pos);
5072 pos += sizeof (gulong);
5077 if (method->save_lmf) {
5078 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5079 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5080 g_assert (mips_is_imm16(offset));
5081 mips_swc1 (code, i, mips_sp, offset);
5086 if (cfg->frame_reg != mips_sp) {
5087 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5088 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5090 if (method->save_lmf) {
5091 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5092 g_assert (mips_is_imm16(offset));
5093 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5097 /* store runtime generic context */
5098 if (cfg->rgctx_var) {
5099 MonoInst *ins = cfg->rgctx_var;
5101 g_assert (ins->opcode == OP_REGOFFSET);
5103 g_assert (mips_is_imm16 (ins->inst_offset));
5104 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5107 /* load arguments allocated to register from the stack */
5110 if (!cfg->arch.cinfo)
5111 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
5112 cinfo = cfg->arch.cinfo;
5114 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5115 ArgInfo *ainfo = &cinfo->ret;
5116 inst = cfg->vret_addr;
5117 if (inst->opcode == OP_REGVAR)
5118 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5119 else if (mips_is_imm16 (inst->inst_offset)) {
5120 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5122 mips_load_const (code, mips_at, inst->inst_offset);
5123 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5124 mips_sw (code, ainfo->reg, mips_at, 0);
5128 if (sig->call_convention == MONO_CALL_VARARG) {
5129 ArgInfo *cookie = &cinfo->sig_cookie;
5130 int offset = alloc_size + cookie->offset;
5132 /* Save the sig cookie address */
5133 g_assert (cookie->storage == ArgOnStack);
5135 g_assert (mips_is_imm16(offset));
5136 mips_addi (code, mips_at, cfg->frame_reg, offset);
5137 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5140 /* Keep this in sync with emit_load_volatile_arguments */
5141 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5142 ArgInfo *ainfo = cinfo->args + i;
5143 inst = cfg->args [pos];
5145 if (cfg->verbose_level > 2)
5146 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5147 if (inst->opcode == OP_REGVAR) {
5148 /* Argument ends up in a register */
5149 if (ainfo->storage == ArgInIReg)
5150 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5151 else if (ainfo->storage == ArgInFReg) {
5152 g_assert_not_reached();
5154 ppc_fmr (code, inst->dreg, ainfo->reg);
5157 else if (ainfo->storage == ArgOnStack) {
5158 int offset = cfg->stack_usage + ainfo->offset;
5159 g_assert (mips_is_imm16(offset));
5160 mips_lw (code, inst->dreg, mips_sp, offset);
5162 g_assert_not_reached ();
5164 if (cfg->verbose_level > 2)
5165 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5167 /* Argument ends up on the stack */
5168 if (ainfo->storage == ArgInIReg) {
5170 /* Incoming parameters should be above this frame */
5171 if (cfg->verbose_level > 2)
5172 g_print ("stack slot at %d of %d+%d\n",
5173 inst->inst_offset, alloc_size, alloc2_size);
5174 /* g_assert (inst->inst_offset >= alloc_size); */
5175 g_assert (inst->inst_basereg == cfg->frame_reg);
5176 basereg_offset = inst->inst_offset - alloc2_size;
5177 g_assert (mips_is_imm16 (basereg_offset));
5178 switch (ainfo->size) {
5180 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5183 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5187 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5190 #if (SIZEOF_REGISTER == 4)
5191 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5192 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5193 #elif (SIZEOF_REGISTER == 8)
5194 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5198 g_assert_not_reached ();
5201 } else if (ainfo->storage == ArgOnStack) {
5203 * Argument comes in on the stack, and ends up on the stack
5204 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5205 * 8 and 16 bit quantities. Shorten them in place.
5207 g_assert (mips_is_imm16 (inst->inst_offset));
5208 switch (ainfo->size) {
5210 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5211 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5214 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5215 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5222 g_assert_not_reached ();
5224 } else if (ainfo->storage == ArgInFReg) {
5225 g_assert (mips_is_imm16 (inst->inst_offset));
5226 g_assert (mips_is_imm16 (inst->inst_offset+4));
5227 if (ainfo->size == 8) {
5228 #if _MIPS_SIM == _ABIO32
5229 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5230 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5231 #elif _MIPS_SIM == _ABIN32
5232 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5235 else if (ainfo->size == 4)
5236 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5238 g_assert_not_reached ();
5239 } else if (ainfo->storage == ArgStructByVal) {
5241 int doffset = inst->inst_offset;
5243 g_assert (mips_is_imm16 (inst->inst_offset));
5244 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5245 /* Push the argument registers into their stack slots */
5246 for (i = 0; i < ainfo->size; ++i) {
5247 g_assert (mips_is_imm16(doffset));
5248 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5249 doffset += SIZEOF_REGISTER;
5251 } else if (ainfo->storage == ArgStructByAddr) {
5252 g_assert (mips_is_imm16 (inst->inst_offset));
5253 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5254 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5256 g_assert_not_reached ();
5261 if (method->save_lmf) {
5262 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5263 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5265 if (lmf_pthread_key != -1) {
5266 g_assert_not_reached();
5268 emit_tls_access (code, mips_temp, lmf_pthread_key);
5270 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5271 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5272 g_assert (mips_is_imm16(offset));
5273 mips_addiu (code, mips_a0, mips_temp, offset);
5276 /* This can/will clobber the a0-a3 registers */
5277 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5280 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5281 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5282 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5283 /* new_lmf->previous_lmf = *lmf_addr */
5284 mips_lw (code, mips_at, mips_v0, 0);
5285 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5286 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5287 /* *(lmf_addr) = sp + lmf_offset */
5288 g_assert (mips_is_imm16(lmf_offset));
5289 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5290 mips_sw (code, mips_at, mips_v0, 0);
5292 /* save method info */
5293 mips_load_const (code, mips_at, method);
5294 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5295 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5297 /* save the current IP */
5298 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5299 mips_load_const (code, mips_at, 0x01010101);
5300 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5304 if (mips_is_imm16 (-alloc2_size)) {
5305 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5308 mips_load_const (code, mips_at, -alloc2_size);
5309 mips_addu (code, mips_sp, mips_sp, mips_at);
5311 alloc_size += alloc2_size;
5312 cfa_offset += alloc2_size;
5313 if (cfg->frame_reg != mips_sp)
5314 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5316 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5320 #if _MIPS_SIM == _ABIO32
5321 cfg->arch.tracing_offset = cfg->stack_offset;
5322 #elif _MIPS_SIM == _ABIN32
5323 /* no stack slots by default for argument regs, reserve a special block */
5324 g_assert_not_reached ();
5326 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5329 cfg->code_len = code - cfg->native_code;
5330 g_assert (cfg->code_len < cfg->code_size);
5344 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5347 int save_mode = SAVE_NONE;
5349 MonoMethod *method = cfg->method;
5350 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5351 int save_offset = MIPS_STACK_PARAM_OFFSET;
5353 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5355 offset = code - cfg->native_code;
5356 /* we need about 16 instructions */
5357 if (offset > (cfg->code_size - 16 * 4)) {
5358 cfg->code_size *= 2;
5359 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5360 code = cfg->native_code + offset;
5365 case MONO_TYPE_VOID:
5366 /* special case string .ctor icall */
5367 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5368 save_mode = SAVE_ONE;
5370 save_mode = SAVE_NONE;
5374 save_mode = SAVE_FP;
5376 case MONO_TYPE_VALUETYPE:
5377 save_mode = SAVE_STRUCT;
5381 #if SIZEOF_REGISTER == 4
5382 save_mode = SAVE_TWO;
5383 #elif SIZEOF_REGISTER == 8
5384 save_mode = SAVE_ONE;
5388 save_mode = SAVE_ONE;
5392 mips_addiu (code, mips_sp, mips_sp, -32);
5393 g_assert (mips_is_imm16(save_offset));
5394 switch (save_mode) {
5396 mips_sw (code, mips_v0, mips_sp, save_offset);
5397 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5398 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5399 if (enable_arguments) {
5400 MIPS_MOVE (code, mips_a1, mips_v0);
5401 MIPS_MOVE (code, mips_a2, mips_v1);
5405 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5406 if (enable_arguments) {
5407 MIPS_MOVE (code, mips_a1, mips_v0);
5411 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5412 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5413 mips_lw (code, mips_a0, mips_sp, save_offset);
5414 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5415 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5422 mips_load_const (code, mips_a0, cfg->method);
5423 mips_call (code, mips_t9, func);
5425 switch (save_mode) {
5427 mips_lw (code, mips_v0, mips_sp, save_offset);
5428 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5429 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5432 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5435 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5442 mips_addiu (code, mips_sp, mips_sp, 32);
5449 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5451 MonoMethod *method = cfg->method;
5453 int max_epilog_size = 16 + 20*4;
5454 int alloc2_size = 0;
5455 guint32 iregs_to_restore;
5457 guint32 fregs_to_restore;
5460 if (cfg->method->save_lmf)
5461 max_epilog_size += 128;
5463 if (mono_jit_trace_calls != NULL)
5464 max_epilog_size += 50;
5466 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5467 max_epilog_size += 50;
5470 pos = code - cfg->native_code;
5471 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5472 cfg->code_size *= 2;
5473 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5474 cfg->stat_code_reallocs++;
5478 * Keep in sync with OP_JMP
5481 code = cfg->native_code + pos;
5483 code = cfg->native_code + cfg->code_len;
5485 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5486 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5488 if (cfg->frame_reg != mips_sp) {
5489 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5491 /* If the stack frame is really large, deconstruct it in two steps */
5492 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5493 alloc2_size = cfg->stack_usage - 1024;
5494 /* partially deconstruct the stack */
5495 mips_load_const (code, mips_at, alloc2_size);
5496 mips_addu (code, mips_sp, mips_sp, mips_at);
5498 pos = cfg->arch.iregs_offset - alloc2_size;
5499 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5500 if (iregs_to_restore) {
5501 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5502 if (iregs_to_restore & (1 << i)) {
5503 g_assert (mips_is_imm16(pos));
5504 MIPS_LW (code, i, mips_sp, pos);
5505 pos += SIZEOF_REGISTER;
5512 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5514 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5515 fregs_to_restore |= (fregs_to_restore << 1);
5517 if (fregs_to_restore) {
5518 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5519 if (fregs_to_restore & (1 << i)) {
5520 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5521 g_assert (mips_is_imm16(pos));
5522 mips_lwc1 (code, i, mips_sp, pos);
5529 /* Unlink the LMF if necessary */
5530 if (method->save_lmf) {
5531 int lmf_offset = cfg->arch.lmf_offset;
5533 /* t0 = current_lmf->previous_lmf */
5534 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5535 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5537 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5538 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5539 /* (*lmf_addr) = previous_lmf */
5540 mips_sw (code, mips_temp, mips_t1, 0);
5544 /* Restore the fp */
5545 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5548 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5549 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5550 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5552 /* Restore the stack pointer */
5553 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5554 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5556 /* Caller will emit either return or tail-call sequence */
5558 cfg->code_len = code - cfg->native_code;
5560 g_assert (cfg->code_len < cfg->code_size);
5565 mono_arch_emit_epilog (MonoCompile *cfg)
5569 code = mono_arch_emit_epilog_sub (cfg, NULL);
5571 mips_jr (code, mips_ra);
5574 cfg->code_len = code - cfg->native_code;
5576 g_assert (cfg->code_len < cfg->code_size);
5579 /* remove once throw_exception_by_name is eliminated */
5582 exception_id_by_name (const char *name)
5584 if (strcmp (name, "IndexOutOfRangeException") == 0)
5585 return MONO_EXC_INDEX_OUT_OF_RANGE;
5586 if (strcmp (name, "OverflowException") == 0)
5587 return MONO_EXC_OVERFLOW;
5588 if (strcmp (name, "ArithmeticException") == 0)
5589 return MONO_EXC_ARITHMETIC;
5590 if (strcmp (name, "DivideByZeroException") == 0)
5591 return MONO_EXC_DIVIDE_BY_ZERO;
5592 if (strcmp (name, "InvalidCastException") == 0)
5593 return MONO_EXC_INVALID_CAST;
5594 if (strcmp (name, "NullReferenceException") == 0)
5595 return MONO_EXC_NULL_REF;
5596 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5597 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5598 if (strcmp (name, "ArgumentException") == 0)
5599 return MONO_EXC_ARGUMENT;
5600 g_error ("Unknown intrinsic exception %s\n", name);
5606 mono_arch_emit_exceptions (MonoCompile *cfg)
5609 MonoJumpInfo *patch_info;
5612 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5613 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5614 int max_epilog_size = 50;
5616 /* count the number of exception infos */
5619 * make sure we have enough space for exceptions
5620 * 24 is the simulated call to throw_exception_by_name
5622 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5624 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5625 i = exception_id_by_name (patch_info->data.target);
5626 g_assert (i < MONO_EXC_INTRINS_NUM);
5627 if (!exc_throw_found [i]) {
5628 max_epilog_size += 12;
5629 exc_throw_found [i] = TRUE;
5635 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5636 cfg->code_size *= 2;
5637 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5638 cfg->stat_code_reallocs++;
5641 code = cfg->native_code + cfg->code_len;
5643 /* add code to raise exceptions */
5644 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5645 switch (patch_info->type) {
5646 case MONO_PATCH_INFO_EXC: {
5648 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5650 i = exception_id_by_name (patch_info->data.target);
5651 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5652 if (!exc_throw_pos [i]) {
5655 exc_throw_pos [i] = code;
5656 //g_print ("exc: writing stub at %p\n", code);
5657 mips_load_const (code, mips_a0, patch_info->data.target);
5658 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5659 mips_load_const (code, mips_t9, addr);
5660 mips_jr (code, mips_t9);
5663 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5665 /* Turn into a Relative patch, pointing at code stub */
5666 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5667 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5669 g_assert_not_reached();
5679 cfg->code_len = code - cfg->native_code;
5681 g_assert (cfg->code_len < cfg->code_size);
5686 * Thread local storage support
5689 setup_tls_access (void)
5692 //guint32 *ins, *code;
5694 if (tls_mode == TLS_MODE_FAILED)
5697 if (g_getenv ("MONO_NO_TLS")) {
5698 tls_mode = TLS_MODE_FAILED;
5702 if (tls_mode == TLS_MODE_DETECT) {
5704 tls_mode = TLS_MODE_FAILED;
5708 ins = (guint32*)pthread_getspecific;
5709 /* uncond branch to the real method */
5710 if ((*ins >> 26) == 18) {
5712 val = (*ins & ~3) << 6;
5716 ins = (guint32*)val;
5718 ins = (guint32*) ((char*)ins + val);
5721 code = &cmplwi_1023;
5722 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5724 ppc_li (code, ppc_r4, 0x48);
5727 if (*ins == cmplwi_1023) {
5728 int found_lwz_284 = 0;
5729 for (ptk = 0; ptk < 20; ++ptk) {
5731 if (!*ins || *ins == blr_ins)
5733 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5738 if (!found_lwz_284) {
5739 tls_mode = TLS_MODE_FAILED;
5742 tls_mode = TLS_MODE_LTHREADS;
5743 } else if (*ins == li_0x48) {
5745 /* uncond branch to the real method */
5746 if ((*ins >> 26) == 18) {
5748 val = (*ins & ~3) << 6;
5752 ins = (guint32*)val;
5754 ins = (guint32*) ((char*)ins + val);
5757 ppc_li (code, ppc_r0, 0x7FF2);
5758 if (ins [1] == val) {
5759 /* Darwin on G4, implement */
5760 tls_mode = TLS_MODE_FAILED;
5764 ppc_mfspr (code, ppc_r3, 104);
5765 if (ins [1] != val) {
5766 tls_mode = TLS_MODE_FAILED;
5769 tls_mode = TLS_MODE_DARWIN_G5;
5772 tls_mode = TLS_MODE_FAILED;
5776 tls_mode = TLS_MODE_FAILED;
5781 if (lmf_pthread_key == -1) {
5782 ptk = mono_jit_tls_id;
5784 /*g_print ("MonoLMF at: %d\n", ptk);*/
5785 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5786 init_tls_failed = 1;
5789 lmf_pthread_key = ptk;
5792 if (monothread_key == -1) {
5793 ptk = mono_thread_get_tls_key ();
5795 monothread_key = ptk;
5796 /*g_print ("thread inited: %d\n", ptk);*/
5798 /*g_print ("thread not inited yet %d\n", ptk);*/
5804 mono_arch_finish_init (void)
5806 setup_tls_access ();
5810 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5815 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5817 int this_dreg = mips_a0;
5820 this_dreg = mips_a1;
5822 /* add the this argument */
5823 if (this_reg != -1) {
5825 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5826 this_ins->type = this_type;
5827 this_ins->sreg1 = this_reg;
5828 this_ins->dreg = mono_alloc_ireg (cfg);
5829 mono_bblock_add_inst (cfg->cbb, this_ins);
5830 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5835 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5836 vtarg->type = STACK_MP;
5837 vtarg->sreg1 = vt_reg;
5838 vtarg->dreg = mono_alloc_ireg (cfg);
5839 mono_bblock_add_inst (cfg->cbb, vtarg);
5840 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5845 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5847 MonoInst *ins = NULL;
5853 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5859 mono_arch_print_tree (MonoInst *tree, int arity)
5865 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5867 return ctx->sc_regs [reg];
5870 #define ENABLE_WRONG_METHOD_CHECK 0
5872 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5873 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5875 #define LOADSTORE_SIZE 4
5876 #define JUMP_IMM_SIZE 16
5877 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5878 #define LOAD_CONST_SIZE 8
5879 #define JUMP_JR_SIZE 8
5882 * LOCKING: called with the domain lock held
5885 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5886 gpointer fail_tramp)
5890 guint8 *code, *start, *patch;
5892 for (i = 0; i < count; ++i) {
5893 MonoIMTCheckItem *item = imt_entries [i];
5895 if (item->is_equals) {
5896 if (item->check_target_idx) {
5897 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5898 if (item->has_target_code)
5899 item->chunk_size += LOAD_CONST_SIZE;
5901 item->chunk_size += LOADSTORE_SIZE;
5904 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5905 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5906 if (!item->has_target_code)
5907 item->chunk_size += LOADSTORE_SIZE;
5909 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5910 #if ENABLE_WRONG_METHOD_CHECK
5911 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5916 item->chunk_size += CMP_SIZE + BR_SIZE;
5917 imt_entries [item->check_target_idx]->compare_done = TRUE;
5919 size += item->chunk_size;
5921 /* the initial load of the vtable address */
5922 size += MIPS_LOAD_SEQUENCE_LENGTH;
5924 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5926 code = mono_domain_code_reserve (domain, size);
5930 /* t7 points to the vtable */
5931 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5933 for (i = 0; i < count; ++i) {
5934 MonoIMTCheckItem *item = imt_entries [i];
5936 item->code_target = code;
5937 if (item->is_equals) {
5938 if (item->check_target_idx) {
5939 mips_load_const (code, mips_temp, (gsize)item->key);
5940 item->jmp_code = code;
5941 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5943 if (item->has_target_code) {
5944 mips_load_const (code, mips_t9,
5945 item->value.target_code);
5948 mips_lw (code, mips_t9, mips_t7,
5949 (sizeof (gpointer) * item->value.vtable_slot));
5951 mips_jr (code, mips_t9);
5955 mips_load_const (code, mips_temp, (gsize)item->key);
5957 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5959 if (item->has_target_code) {
5960 mips_load_const (code, mips_t9,
5961 item->value.target_code);
5964 mips_load_const (code, mips_at,
5965 & (vtable->vtable [item->value.vtable_slot]));
5966 mips_lw (code, mips_t9, mips_at, 0);
5968 mips_jr (code, mips_t9);
5970 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5971 mips_load_const (code, mips_t9, fail_tramp);
5972 mips_jr (code, mips_t9);
5975 /* enable the commented code to assert on wrong method */
5976 #if ENABLE_WRONG_METHOD_CHECK
5977 ppc_load (code, ppc_r0, (guint32)item->key);
5978 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5980 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5982 mips_lw (code, mips_t9, mips_t7,
5983 (sizeof (gpointer) * item->value.vtable_slot));
5984 mips_jr (code, mips_t9);
5987 #if ENABLE_WRONG_METHOD_CHECK
5988 ppc_patch (patch, code);
5994 mips_load_const (code, mips_temp, (gulong)item->key);
5995 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5997 item->jmp_code = code;
5998 mips_beq (code, mips_temp, mips_zero, 0);
6002 /* patch the branches to get to the target items */
6003 for (i = 0; i < count; ++i) {
6004 MonoIMTCheckItem *item = imt_entries [i];
6005 if (item->jmp_code && item->check_target_idx) {
6006 mips_patch ((guint32 *)item->jmp_code,
6007 (guint32)imt_entries [item->check_target_idx]->code_target);
6012 mono_stats.imt_thunks_size += code - start;
6013 g_assert (code - start <= size);
6014 mono_arch_flush_icache (start, size);
6016 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
6022 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6024 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6028 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6030 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6033 /* Soft Debug support */
6034 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6037 * mono_arch_set_breakpoint:
6039 * See mini-amd64.c for docs.
6042 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6045 guint32 addr = (guint32)bp_trigger_page;
6047 mips_load_const (code, mips_t9, addr);
6048 mips_lw (code, mips_t9, mips_t9, 0);
6050 mono_arch_flush_icache (ip, code - ip);
6054 * mono_arch_clear_breakpoint:
6056 * See mini-amd64.c for docs.
6059 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6067 mono_arch_flush_icache (ip, code - ip);
6071 * mono_arch_start_single_stepping:
6073 * See mini-amd64.c for docs.
6076 mono_arch_start_single_stepping (void)
6078 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6082 * mono_arch_stop_single_stepping:
6084 * See mini-amd64.c for docs.
6087 mono_arch_stop_single_stepping (void)
6089 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6093 * mono_arch_is_single_step_event:
6095 * See mini-amd64.c for docs.
6098 mono_arch_is_single_step_event (void *info, void *sigctx)
6100 siginfo_t* sinfo = (siginfo_t*) info;
6101 /* Sometimes the address is off by 4 */
6102 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6109 * mono_arch_is_breakpoint_event:
6111 * See mini-amd64.c for docs.
6114 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6116 siginfo_t* sinfo = (siginfo_t*) info;
6117 /* Sometimes the address is off by 4 */
6118 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6125 * mono_arch_skip_breakpoint:
6127 * See mini-amd64.c for docs.
6130 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6132 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6136 * mono_arch_skip_single_step:
6138 * See mini-amd64.c for docs.
6141 mono_arch_skip_single_step (MonoContext *ctx)
6143 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6147 * mono_arch_get_seq_point_info:
6149 * See mini-amd64.c for docs.
6152 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6159 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6161 ext->lmf.previous_lmf = prev_lmf;
6162 /* Mark that this is a MonoLMFExt */
6163 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6164 ext->lmf.iregs [mips_sp] = (gssize)ext;
6167 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
6170 mono_arch_opcode_supported (int opcode)