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);
4646 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4647 g_assert_not_reached ();
4650 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4651 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4652 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4653 g_assert_not_reached ();
4659 last_offset = offset;
4662 cfg->code_len = code - cfg->native_code;
4666 mono_arch_register_lowlevel_calls (void)
4671 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4673 MonoJumpInfo *patch_info;
4675 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4676 unsigned char *ip = patch_info->ip.i + code;
4677 const unsigned char *target = NULL;
4679 switch (patch_info->type) {
4680 case MONO_PATCH_INFO_IP:
4681 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4683 case MONO_PATCH_INFO_SWITCH: {
4684 gpointer *table = (gpointer *)patch_info->data.table->table;
4687 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4689 for (i = 0; i < patch_info->data.table->table_size; i++) {
4690 table [i] = (int)patch_info->data.table->table [i] + code;
4694 case MONO_PATCH_INFO_METHODCONST:
4695 case MONO_PATCH_INFO_CLASS:
4696 case MONO_PATCH_INFO_IMAGE:
4697 case MONO_PATCH_INFO_FIELD:
4698 case MONO_PATCH_INFO_VTABLE:
4699 case MONO_PATCH_INFO_IID:
4700 case MONO_PATCH_INFO_SFLDA:
4701 case MONO_PATCH_INFO_LDSTR:
4702 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4703 case MONO_PATCH_INFO_LDTOKEN:
4704 case MONO_PATCH_INFO_R4:
4705 case MONO_PATCH_INFO_R8:
4706 /* from OP_AOTCONST : lui + addiu */
4707 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4708 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4711 case MONO_PATCH_INFO_EXC_NAME:
4712 g_assert_not_reached ();
4713 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4716 case MONO_PATCH_INFO_NONE:
4717 /* everything is dealt with at epilog output time */
4720 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4721 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4728 * Allow tracing to work with this interface (with an optional argument)
4730 * This code is expected to be inserted just after the 'real' prolog code,
4731 * and before the first basic block. We need to allocate a 2nd, temporary
4732 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4736 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4739 int offset = cfg->arch.tracing_offset;
4745 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4746 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4747 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4748 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4749 #if _MIPS_SIM == _ABIN32
4751 /* FIXME: Need a separate region for these */
4752 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4753 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4754 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4755 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4759 mips_load_const (code, mips_a0, cfg->method);
4760 mips_addiu (code, mips_a1, mips_sp, offset);
4761 mips_call (code, mips_t9, func);
4764 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4765 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4766 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4767 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4768 #if _MIPS_SIM == _ABIN32
4771 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4772 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4773 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4774 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4785 mips_adjust_stackframe(MonoCompile *cfg)
4788 int delta, threshold, i;
4789 MonoMethodSignature *sig;
4792 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4795 /* adjust cfg->stack_offset for account for down-spilling */
4796 cfg->stack_offset += SIZEOF_REGISTER;
4798 /* re-align cfg->stack_offset if needed (due to var spilling) */
4799 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4800 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4801 if (cfg->verbose_level > 2) {
4802 g_print ("mips_adjust_stackframe:\n");
4803 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4805 threshold = cfg->arch.local_alloc_offset;
4806 ra_offset = cfg->stack_offset - sizeof(gpointer);
4807 if (cfg->verbose_level > 2) {
4808 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4811 sig = mono_method_signature (cfg->method);
4812 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4813 cfg->vret_addr->inst_offset += delta;
4815 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4816 MonoInst *inst = cfg->args [i];
4818 inst->inst_offset += delta;
4822 * loads and stores based off the frame reg that (used to) lie
4823 * above the spill var area need to be increased by 'delta'
4824 * to make room for the spill vars.
4826 /* Need to find loads and stores to adjust that
4827 * are above where the spillvars were inserted, but
4828 * which are not the spillvar references themselves.
4830 * Idea - since all offsets from fp are positive, make
4831 * spillvar offsets negative to begin with so we can spot
4836 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4840 if (cfg->verbose_level > 2) {
4841 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4843 MONO_BB_FOR_EACH_INS (bb, ins) {
4847 if (cfg->verbose_level > 2) {
4848 mono_print_ins_index (ins_cnt, ins);
4850 /* The == mips_sp tests catch FP spills */
4851 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4852 (ins->inst_basereg == mips_sp))) {
4853 switch (ins->opcode) {
4854 case OP_LOADI8_MEMBASE:
4855 case OP_LOADR8_MEMBASE:
4862 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4863 (ins->dreg == mips_sp))) {
4864 switch (ins->opcode) {
4865 case OP_STOREI8_MEMBASE_REG:
4866 case OP_STORER8_MEMBASE_REG:
4867 case OP_STOREI8_MEMBASE_IMM:
4875 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4878 if (ins->inst_c0 >= threshold) {
4879 ins->inst_c0 += delta;
4880 if (cfg->verbose_level > 2) {
4882 mono_print_ins_index (ins_cnt, ins);
4885 else if (ins->inst_c0 < 0) {
4886 /* Adj_c0 holds the size of the datatype. */
4887 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4888 if (cfg->verbose_level > 2) {
4890 mono_print_ins_index (ins_cnt, ins);
4893 g_assert (ins->inst_c0 != ra_offset);
4896 if (ins->inst_imm >= threshold) {
4897 ins->inst_imm += delta;
4898 if (cfg->verbose_level > 2) {
4900 mono_print_ins_index (ins_cnt, ins);
4903 g_assert (ins->inst_c0 != ra_offset);
4913 * Stack frame layout:
4915 * ------------------- sp + cfg->stack_usage + cfg->param_area
4916 * param area incoming
4917 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4919 * ------------------- sp + cfg->stack_usage
4921 * ------------------- sp + cfg->stack_usage-4
4923 * ------------------- sp +
4924 * MonoLMF structure optional
4925 * ------------------- sp + cfg->arch.lmf_offset
4926 * saved registers s0-s8
4927 * ------------------- sp + cfg->arch.iregs_offset
4929 * ------------------- sp + cfg->param_area
4930 * param area outgoing
4931 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4933 * ------------------- sp
4937 mono_arch_emit_prolog (MonoCompile *cfg)
4939 MonoMethod *method = cfg->method;
4940 MonoMethodSignature *sig;
4942 int alloc_size, pos, i, max_offset;
4943 int alloc2_size = 0;
4947 guint32 iregs_to_save = 0;
4949 guint32 fregs_to_save = 0;
4951 /* lmf_offset is the offset of the LMF from our stack pointer. */
4952 guint32 lmf_offset = cfg->arch.lmf_offset;
4956 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4960 cfg->flags |= MONO_CFG_HAS_CALLS;
4962 sig = mono_method_signature (method);
4963 cfg->code_size = 768 + sig->param_count * 20;
4964 code = cfg->native_code = g_malloc (cfg->code_size);
4967 * compute max_offset in order to use short forward jumps.
4970 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4971 MonoInst *ins = bb->code;
4972 bb->max_offset = max_offset;
4974 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4977 MONO_BB_FOR_EACH_INS (bb, ins)
4978 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4980 if (max_offset > 0xffff)
4981 cfg->arch.long_branch = TRUE;
4984 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4985 * This means that we have to adjust the offsets inside instructions which reference
4986 * arguments received on the stack, since the initial offset doesn't take into
4987 * account spill slots.
4989 mips_adjust_stackframe (cfg);
4991 /* Offset between current sp and the CFA */
4993 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4995 /* stack_offset should not be changed here. */
4996 alloc_size = cfg->stack_offset;
4997 cfg->stack_usage = alloc_size;
4999 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5002 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5004 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
5005 fregs_to_save |= (fregs_to_save << 1);
5008 /* If the stack size is too big, save 1024 bytes to start with
5009 * so the prologue can use imm16(reg) addressing, then allocate
5010 * the rest of the frame.
5012 if (alloc_size > ((1 << 15) - 1024)) {
5013 alloc2_size = alloc_size - 1024;
5017 g_assert (mips_is_imm16 (-alloc_size));
5018 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
5019 cfa_offset = alloc_size;
5020 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5023 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5024 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5025 if (mips_is_imm16(offset))
5026 mips_sw (code, mips_ra, mips_sp, offset);
5028 g_assert_not_reached ();
5030 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5031 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5034 /* XXX - optimize this later to not save all regs if LMF constructed */
5035 pos = cfg->arch.iregs_offset - alloc2_size;
5037 if (iregs_to_save) {
5038 /* save used registers in own stack frame (at pos) */
5039 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5040 if (iregs_to_save & (1 << i)) {
5041 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5042 g_assert (mips_is_imm16(pos));
5043 MIPS_SW (code, i, mips_sp, pos);
5044 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5045 pos += SIZEOF_REGISTER;
5050 // FIXME: Don't save registers twice if there is an LMF
5051 // s8 has to be special cased since it is overwritten with the updated value
5053 if (method->save_lmf) {
5054 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5055 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5056 g_assert (mips_is_imm16(offset));
5057 if (MIPS_LMF_IREGMASK & (1 << i))
5058 MIPS_SW (code, i, mips_sp, offset);
5063 /* Save float registers */
5064 if (fregs_to_save) {
5065 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5066 if (fregs_to_save & (1 << i)) {
5067 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5068 g_assert (mips_is_imm16(pos));
5069 mips_swc1 (code, i, mips_sp, pos);
5070 pos += sizeof (gulong);
5075 if (method->save_lmf) {
5076 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5077 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5078 g_assert (mips_is_imm16(offset));
5079 mips_swc1 (code, i, mips_sp, offset);
5084 if (cfg->frame_reg != mips_sp) {
5085 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5086 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5088 if (method->save_lmf) {
5089 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5090 g_assert (mips_is_imm16(offset));
5091 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5095 /* store runtime generic context */
5096 if (cfg->rgctx_var) {
5097 MonoInst *ins = cfg->rgctx_var;
5099 g_assert (ins->opcode == OP_REGOFFSET);
5101 g_assert (mips_is_imm16 (ins->inst_offset));
5102 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5105 /* load arguments allocated to register from the stack */
5108 if (!cfg->arch.cinfo)
5109 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
5110 cinfo = cfg->arch.cinfo;
5112 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5113 ArgInfo *ainfo = &cinfo->ret;
5114 inst = cfg->vret_addr;
5115 if (inst->opcode == OP_REGVAR)
5116 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5117 else if (mips_is_imm16 (inst->inst_offset)) {
5118 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5120 mips_load_const (code, mips_at, inst->inst_offset);
5121 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5122 mips_sw (code, ainfo->reg, mips_at, 0);
5126 if (sig->call_convention == MONO_CALL_VARARG) {
5127 ArgInfo *cookie = &cinfo->sig_cookie;
5128 int offset = alloc_size + cookie->offset;
5130 /* Save the sig cookie address */
5131 g_assert (cookie->storage == ArgOnStack);
5133 g_assert (mips_is_imm16(offset));
5134 mips_addi (code, mips_at, cfg->frame_reg, offset);
5135 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5138 /* Keep this in sync with emit_load_volatile_arguments */
5139 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5140 ArgInfo *ainfo = cinfo->args + i;
5141 inst = cfg->args [pos];
5143 if (cfg->verbose_level > 2)
5144 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5145 if (inst->opcode == OP_REGVAR) {
5146 /* Argument ends up in a register */
5147 if (ainfo->storage == ArgInIReg)
5148 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5149 else if (ainfo->storage == ArgInFReg) {
5150 g_assert_not_reached();
5152 ppc_fmr (code, inst->dreg, ainfo->reg);
5155 else if (ainfo->storage == ArgOnStack) {
5156 int offset = cfg->stack_usage + ainfo->offset;
5157 g_assert (mips_is_imm16(offset));
5158 mips_lw (code, inst->dreg, mips_sp, offset);
5160 g_assert_not_reached ();
5162 if (cfg->verbose_level > 2)
5163 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5165 /* Argument ends up on the stack */
5166 if (ainfo->storage == ArgInIReg) {
5168 /* Incoming parameters should be above this frame */
5169 if (cfg->verbose_level > 2)
5170 g_print ("stack slot at %d of %d+%d\n",
5171 inst->inst_offset, alloc_size, alloc2_size);
5172 /* g_assert (inst->inst_offset >= alloc_size); */
5173 g_assert (inst->inst_basereg == cfg->frame_reg);
5174 basereg_offset = inst->inst_offset - alloc2_size;
5175 g_assert (mips_is_imm16 (basereg_offset));
5176 switch (ainfo->size) {
5178 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5181 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5185 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5188 #if (SIZEOF_REGISTER == 4)
5189 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5190 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5191 #elif (SIZEOF_REGISTER == 8)
5192 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5196 g_assert_not_reached ();
5199 } else if (ainfo->storage == ArgOnStack) {
5201 * Argument comes in on the stack, and ends up on the stack
5202 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5203 * 8 and 16 bit quantities. Shorten them in place.
5205 g_assert (mips_is_imm16 (inst->inst_offset));
5206 switch (ainfo->size) {
5208 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5209 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5212 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5213 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5220 g_assert_not_reached ();
5222 } else if (ainfo->storage == ArgInFReg) {
5223 g_assert (mips_is_imm16 (inst->inst_offset));
5224 g_assert (mips_is_imm16 (inst->inst_offset+4));
5225 if (ainfo->size == 8) {
5226 #if _MIPS_SIM == _ABIO32
5227 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5228 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5229 #elif _MIPS_SIM == _ABIN32
5230 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5233 else if (ainfo->size == 4)
5234 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5236 g_assert_not_reached ();
5237 } else if (ainfo->storage == ArgStructByVal) {
5239 int doffset = inst->inst_offset;
5241 g_assert (mips_is_imm16 (inst->inst_offset));
5242 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5243 /* Push the argument registers into their stack slots */
5244 for (i = 0; i < ainfo->size; ++i) {
5245 g_assert (mips_is_imm16(doffset));
5246 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5247 doffset += SIZEOF_REGISTER;
5249 } else if (ainfo->storage == ArgStructByAddr) {
5250 g_assert (mips_is_imm16 (inst->inst_offset));
5251 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5252 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5254 g_assert_not_reached ();
5259 if (method->save_lmf) {
5260 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5261 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5263 if (lmf_pthread_key != -1) {
5264 g_assert_not_reached();
5266 emit_tls_access (code, mips_temp, lmf_pthread_key);
5268 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5269 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5270 g_assert (mips_is_imm16(offset));
5271 mips_addiu (code, mips_a0, mips_temp, offset);
5274 /* This can/will clobber the a0-a3 registers */
5275 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5278 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5279 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5280 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5281 /* new_lmf->previous_lmf = *lmf_addr */
5282 mips_lw (code, mips_at, mips_v0, 0);
5283 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5284 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5285 /* *(lmf_addr) = sp + lmf_offset */
5286 g_assert (mips_is_imm16(lmf_offset));
5287 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5288 mips_sw (code, mips_at, mips_v0, 0);
5290 /* save method info */
5291 mips_load_const (code, mips_at, method);
5292 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5293 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5295 /* save the current IP */
5296 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5297 mips_load_const (code, mips_at, 0x01010101);
5298 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5302 if (mips_is_imm16 (-alloc2_size)) {
5303 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5306 mips_load_const (code, mips_at, -alloc2_size);
5307 mips_addu (code, mips_sp, mips_sp, mips_at);
5309 alloc_size += alloc2_size;
5310 cfa_offset += alloc2_size;
5311 if (cfg->frame_reg != mips_sp)
5312 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5314 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5318 #if _MIPS_SIM == _ABIO32
5319 cfg->arch.tracing_offset = cfg->stack_offset;
5320 #elif _MIPS_SIM == _ABIN32
5321 /* no stack slots by default for argument regs, reserve a special block */
5322 g_assert_not_reached ();
5324 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5327 cfg->code_len = code - cfg->native_code;
5328 g_assert (cfg->code_len < cfg->code_size);
5342 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5345 int save_mode = SAVE_NONE;
5347 MonoMethod *method = cfg->method;
5348 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5349 int save_offset = MIPS_STACK_PARAM_OFFSET;
5351 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5353 offset = code - cfg->native_code;
5354 /* we need about 16 instructions */
5355 if (offset > (cfg->code_size - 16 * 4)) {
5356 cfg->code_size *= 2;
5357 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5358 code = cfg->native_code + offset;
5363 case MONO_TYPE_VOID:
5364 /* special case string .ctor icall */
5365 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5366 save_mode = SAVE_ONE;
5368 save_mode = SAVE_NONE;
5372 save_mode = SAVE_FP;
5374 case MONO_TYPE_VALUETYPE:
5375 save_mode = SAVE_STRUCT;
5379 #if SIZEOF_REGISTER == 4
5380 save_mode = SAVE_TWO;
5381 #elif SIZEOF_REGISTER == 8
5382 save_mode = SAVE_ONE;
5386 save_mode = SAVE_ONE;
5390 mips_addiu (code, mips_sp, mips_sp, -32);
5391 g_assert (mips_is_imm16(save_offset));
5392 switch (save_mode) {
5394 mips_sw (code, mips_v0, mips_sp, save_offset);
5395 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5396 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5397 if (enable_arguments) {
5398 MIPS_MOVE (code, mips_a1, mips_v0);
5399 MIPS_MOVE (code, mips_a2, mips_v1);
5403 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5404 if (enable_arguments) {
5405 MIPS_MOVE (code, mips_a1, mips_v0);
5409 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5410 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5411 mips_lw (code, mips_a0, mips_sp, save_offset);
5412 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5413 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5420 mips_load_const (code, mips_a0, cfg->method);
5421 mips_call (code, mips_t9, func);
5423 switch (save_mode) {
5425 mips_lw (code, mips_v0, mips_sp, save_offset);
5426 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5427 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5430 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5433 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5440 mips_addiu (code, mips_sp, mips_sp, 32);
5447 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5449 MonoMethod *method = cfg->method;
5451 int max_epilog_size = 16 + 20*4;
5452 int alloc2_size = 0;
5453 guint32 iregs_to_restore;
5455 guint32 fregs_to_restore;
5458 if (cfg->method->save_lmf)
5459 max_epilog_size += 128;
5461 if (mono_jit_trace_calls != NULL)
5462 max_epilog_size += 50;
5464 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5465 max_epilog_size += 50;
5468 pos = code - cfg->native_code;
5469 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5470 cfg->code_size *= 2;
5471 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5472 cfg->stat_code_reallocs++;
5476 * Keep in sync with OP_JMP
5479 code = cfg->native_code + pos;
5481 code = cfg->native_code + cfg->code_len;
5483 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5484 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5486 if (cfg->frame_reg != mips_sp) {
5487 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5489 /* If the stack frame is really large, deconstruct it in two steps */
5490 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5491 alloc2_size = cfg->stack_usage - 1024;
5492 /* partially deconstruct the stack */
5493 mips_load_const (code, mips_at, alloc2_size);
5494 mips_addu (code, mips_sp, mips_sp, mips_at);
5496 pos = cfg->arch.iregs_offset - alloc2_size;
5497 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5498 if (iregs_to_restore) {
5499 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5500 if (iregs_to_restore & (1 << i)) {
5501 g_assert (mips_is_imm16(pos));
5502 MIPS_LW (code, i, mips_sp, pos);
5503 pos += SIZEOF_REGISTER;
5510 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5512 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5513 fregs_to_restore |= (fregs_to_restore << 1);
5515 if (fregs_to_restore) {
5516 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5517 if (fregs_to_restore & (1 << i)) {
5518 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5519 g_assert (mips_is_imm16(pos));
5520 mips_lwc1 (code, i, mips_sp, pos);
5527 /* Unlink the LMF if necessary */
5528 if (method->save_lmf) {
5529 int lmf_offset = cfg->arch.lmf_offset;
5531 /* t0 = current_lmf->previous_lmf */
5532 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5533 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5535 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5536 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5537 /* (*lmf_addr) = previous_lmf */
5538 mips_sw (code, mips_temp, mips_t1, 0);
5542 /* Restore the fp */
5543 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5546 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5547 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5548 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5550 /* Restore the stack pointer */
5551 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5552 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5554 /* Caller will emit either return or tail-call sequence */
5556 cfg->code_len = code - cfg->native_code;
5558 g_assert (cfg->code_len < cfg->code_size);
5563 mono_arch_emit_epilog (MonoCompile *cfg)
5567 code = mono_arch_emit_epilog_sub (cfg, NULL);
5569 mips_jr (code, mips_ra);
5572 cfg->code_len = code - cfg->native_code;
5574 g_assert (cfg->code_len < cfg->code_size);
5577 /* remove once throw_exception_by_name is eliminated */
5580 exception_id_by_name (const char *name)
5582 if (strcmp (name, "IndexOutOfRangeException") == 0)
5583 return MONO_EXC_INDEX_OUT_OF_RANGE;
5584 if (strcmp (name, "OverflowException") == 0)
5585 return MONO_EXC_OVERFLOW;
5586 if (strcmp (name, "ArithmeticException") == 0)
5587 return MONO_EXC_ARITHMETIC;
5588 if (strcmp (name, "DivideByZeroException") == 0)
5589 return MONO_EXC_DIVIDE_BY_ZERO;
5590 if (strcmp (name, "InvalidCastException") == 0)
5591 return MONO_EXC_INVALID_CAST;
5592 if (strcmp (name, "NullReferenceException") == 0)
5593 return MONO_EXC_NULL_REF;
5594 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5595 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5596 if (strcmp (name, "ArgumentException") == 0)
5597 return MONO_EXC_ARGUMENT;
5598 g_error ("Unknown intrinsic exception %s\n", name);
5604 mono_arch_emit_exceptions (MonoCompile *cfg)
5607 MonoJumpInfo *patch_info;
5610 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5611 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5612 int max_epilog_size = 50;
5614 /* count the number of exception infos */
5617 * make sure we have enough space for exceptions
5618 * 24 is the simulated call to throw_exception_by_name
5620 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5622 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5623 i = exception_id_by_name (patch_info->data.target);
5624 g_assert (i < MONO_EXC_INTRINS_NUM);
5625 if (!exc_throw_found [i]) {
5626 max_epilog_size += 12;
5627 exc_throw_found [i] = TRUE;
5633 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5634 cfg->code_size *= 2;
5635 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5636 cfg->stat_code_reallocs++;
5639 code = cfg->native_code + cfg->code_len;
5641 /* add code to raise exceptions */
5642 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5643 switch (patch_info->type) {
5644 case MONO_PATCH_INFO_EXC: {
5646 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5648 i = exception_id_by_name (patch_info->data.target);
5649 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5650 if (!exc_throw_pos [i]) {
5653 exc_throw_pos [i] = code;
5654 //g_print ("exc: writing stub at %p\n", code);
5655 mips_load_const (code, mips_a0, patch_info->data.target);
5656 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5657 mips_load_const (code, mips_t9, addr);
5658 mips_jr (code, mips_t9);
5661 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5663 /* Turn into a Relative patch, pointing at code stub */
5664 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5665 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5667 g_assert_not_reached();
5677 cfg->code_len = code - cfg->native_code;
5679 g_assert (cfg->code_len < cfg->code_size);
5684 * Thread local storage support
5687 setup_tls_access (void)
5690 //guint32 *ins, *code;
5692 if (tls_mode == TLS_MODE_FAILED)
5695 if (g_getenv ("MONO_NO_TLS")) {
5696 tls_mode = TLS_MODE_FAILED;
5700 if (tls_mode == TLS_MODE_DETECT) {
5702 tls_mode = TLS_MODE_FAILED;
5706 ins = (guint32*)pthread_getspecific;
5707 /* uncond branch to the real method */
5708 if ((*ins >> 26) == 18) {
5710 val = (*ins & ~3) << 6;
5714 ins = (guint32*)val;
5716 ins = (guint32*) ((char*)ins + val);
5719 code = &cmplwi_1023;
5720 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5722 ppc_li (code, ppc_r4, 0x48);
5725 if (*ins == cmplwi_1023) {
5726 int found_lwz_284 = 0;
5727 for (ptk = 0; ptk < 20; ++ptk) {
5729 if (!*ins || *ins == blr_ins)
5731 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5736 if (!found_lwz_284) {
5737 tls_mode = TLS_MODE_FAILED;
5740 tls_mode = TLS_MODE_LTHREADS;
5741 } else if (*ins == li_0x48) {
5743 /* uncond branch to the real method */
5744 if ((*ins >> 26) == 18) {
5746 val = (*ins & ~3) << 6;
5750 ins = (guint32*)val;
5752 ins = (guint32*) ((char*)ins + val);
5755 ppc_li (code, ppc_r0, 0x7FF2);
5756 if (ins [1] == val) {
5757 /* Darwin on G4, implement */
5758 tls_mode = TLS_MODE_FAILED;
5762 ppc_mfspr (code, ppc_r3, 104);
5763 if (ins [1] != val) {
5764 tls_mode = TLS_MODE_FAILED;
5767 tls_mode = TLS_MODE_DARWIN_G5;
5770 tls_mode = TLS_MODE_FAILED;
5774 tls_mode = TLS_MODE_FAILED;
5779 if (lmf_pthread_key == -1) {
5780 ptk = mono_jit_tls_id;
5782 /*g_print ("MonoLMF at: %d\n", ptk);*/
5783 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5784 init_tls_failed = 1;
5787 lmf_pthread_key = ptk;
5790 if (monothread_key == -1) {
5791 ptk = mono_thread_get_tls_key ();
5793 monothread_key = ptk;
5794 /*g_print ("thread inited: %d\n", ptk);*/
5796 /*g_print ("thread not inited yet %d\n", ptk);*/
5802 mono_arch_finish_init (void)
5804 setup_tls_access ();
5808 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5813 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5815 int this_dreg = mips_a0;
5818 this_dreg = mips_a1;
5820 /* add the this argument */
5821 if (this_reg != -1) {
5823 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5824 this_ins->type = this_type;
5825 this_ins->sreg1 = this_reg;
5826 this_ins->dreg = mono_alloc_ireg (cfg);
5827 mono_bblock_add_inst (cfg->cbb, this_ins);
5828 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5833 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5834 vtarg->type = STACK_MP;
5835 vtarg->sreg1 = vt_reg;
5836 vtarg->dreg = mono_alloc_ireg (cfg);
5837 mono_bblock_add_inst (cfg->cbb, vtarg);
5838 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5843 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5845 MonoInst *ins = NULL;
5851 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5857 mono_arch_print_tree (MonoInst *tree, int arity)
5863 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5865 return ctx->sc_regs [reg];
5868 #define ENABLE_WRONG_METHOD_CHECK 0
5870 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5871 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5873 #define LOADSTORE_SIZE 4
5874 #define JUMP_IMM_SIZE 16
5875 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5876 #define LOAD_CONST_SIZE 8
5877 #define JUMP_JR_SIZE 8
5880 * LOCKING: called with the domain lock held
5883 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5884 gpointer fail_tramp)
5888 guint8 *code, *start, *patch;
5890 for (i = 0; i < count; ++i) {
5891 MonoIMTCheckItem *item = imt_entries [i];
5893 if (item->is_equals) {
5894 if (item->check_target_idx) {
5895 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5896 if (item->has_target_code)
5897 item->chunk_size += LOAD_CONST_SIZE;
5899 item->chunk_size += LOADSTORE_SIZE;
5902 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5903 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5904 if (!item->has_target_code)
5905 item->chunk_size += LOADSTORE_SIZE;
5907 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5908 #if ENABLE_WRONG_METHOD_CHECK
5909 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5914 item->chunk_size += CMP_SIZE + BR_SIZE;
5915 imt_entries [item->check_target_idx]->compare_done = TRUE;
5917 size += item->chunk_size;
5919 /* the initial load of the vtable address */
5920 size += MIPS_LOAD_SEQUENCE_LENGTH;
5922 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5924 code = mono_domain_code_reserve (domain, size);
5928 /* t7 points to the vtable */
5929 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5931 for (i = 0; i < count; ++i) {
5932 MonoIMTCheckItem *item = imt_entries [i];
5934 item->code_target = code;
5935 if (item->is_equals) {
5936 if (item->check_target_idx) {
5937 mips_load_const (code, mips_temp, (gsize)item->key);
5938 item->jmp_code = code;
5939 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5941 if (item->has_target_code) {
5942 mips_load_const (code, mips_t9,
5943 item->value.target_code);
5946 mips_lw (code, mips_t9, mips_t7,
5947 (sizeof (gpointer) * item->value.vtable_slot));
5949 mips_jr (code, mips_t9);
5953 mips_load_const (code, mips_temp, (gsize)item->key);
5955 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5957 if (item->has_target_code) {
5958 mips_load_const (code, mips_t9,
5959 item->value.target_code);
5962 mips_load_const (code, mips_at,
5963 & (vtable->vtable [item->value.vtable_slot]));
5964 mips_lw (code, mips_t9, mips_at, 0);
5966 mips_jr (code, mips_t9);
5968 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5969 mips_load_const (code, mips_t9, fail_tramp);
5970 mips_jr (code, mips_t9);
5973 /* enable the commented code to assert on wrong method */
5974 #if ENABLE_WRONG_METHOD_CHECK
5975 ppc_load (code, ppc_r0, (guint32)item->key);
5976 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5978 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5980 mips_lw (code, mips_t9, mips_t7,
5981 (sizeof (gpointer) * item->value.vtable_slot));
5982 mips_jr (code, mips_t9);
5985 #if ENABLE_WRONG_METHOD_CHECK
5986 ppc_patch (patch, code);
5992 mips_load_const (code, mips_temp, (gulong)item->key);
5993 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5995 item->jmp_code = code;
5996 mips_beq (code, mips_temp, mips_zero, 0);
6000 /* patch the branches to get to the target items */
6001 for (i = 0; i < count; ++i) {
6002 MonoIMTCheckItem *item = imt_entries [i];
6003 if (item->jmp_code && item->check_target_idx) {
6004 mips_patch ((guint32 *)item->jmp_code,
6005 (guint32)imt_entries [item->check_target_idx]->code_target);
6010 mono_stats.imt_thunks_size += code - start;
6011 g_assert (code - start <= size);
6012 mono_arch_flush_icache (start, size);
6014 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
6020 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6022 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6026 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6028 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6031 /* Soft Debug support */
6032 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6035 * mono_arch_set_breakpoint:
6037 * See mini-amd64.c for docs.
6040 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6043 guint32 addr = (guint32)bp_trigger_page;
6045 mips_load_const (code, mips_t9, addr);
6046 mips_lw (code, mips_t9, mips_t9, 0);
6048 mono_arch_flush_icache (ip, code - ip);
6052 * mono_arch_clear_breakpoint:
6054 * See mini-amd64.c for docs.
6057 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6065 mono_arch_flush_icache (ip, code - ip);
6069 * mono_arch_start_single_stepping:
6071 * See mini-amd64.c for docs.
6074 mono_arch_start_single_stepping (void)
6076 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6080 * mono_arch_stop_single_stepping:
6082 * See mini-amd64.c for docs.
6085 mono_arch_stop_single_stepping (void)
6087 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6091 * mono_arch_is_single_step_event:
6093 * See mini-amd64.c for docs.
6096 mono_arch_is_single_step_event (void *info, void *sigctx)
6098 siginfo_t* sinfo = (siginfo_t*) info;
6099 /* Sometimes the address is off by 4 */
6100 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6107 * mono_arch_is_breakpoint_event:
6109 * See mini-amd64.c for docs.
6112 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6114 siginfo_t* sinfo = (siginfo_t*) info;
6115 /* Sometimes the address is off by 4 */
6116 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6123 * mono_arch_skip_breakpoint:
6125 * See mini-amd64.c for docs.
6128 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6130 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6134 * mono_arch_skip_single_step:
6136 * See mini-amd64.c for docs.
6139 mono_arch_skip_single_step (MonoContext *ctx)
6141 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6145 * mono_arch_get_seq_point_info:
6147 * See mini-amd64.c for docs.
6150 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6157 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6159 ext->lmf.previous_lmf = prev_lmf;
6160 /* Mark that this is a MonoLMFExt */
6161 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6162 ext->lmf.iregs [mips_sp] = (gssize)ext;
6165 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
6168 mono_arch_opcode_supported (int opcode)