2 * mini-mips.c: MIPS backend for the Mono code generator
5 * Mark Mason (mason@broadcom.com)
7 * Based on mini-ppc.c by
8 * Paolo Molaro (lupus@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2003 Ximian, Inc.
16 #include <asm/cachectl.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/utils/mono-mmap.h>
22 #include <mono/arch/mips/mips-codegen.h>
24 #include "mini-mips.h"
29 #define SAVE_FP_REGS 0
31 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
33 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
34 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
35 remember to update cpu-mips.md if you change this */
37 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
38 #define mips_call(c,D,v) do { \
39 guint32 _target = (guint32)(v); \
40 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
41 mips_load_const (c, D, _target); \
42 mips_jalr (c, D, mips_ra); \
45 mips_jumpl (c, _target >> 2); \
57 /* This mutex protects architecture specific caches */
58 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
59 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
60 static CRITICAL_SECTION mini_arch_mutex;
62 int mono_exc_esp_offset = 0;
63 static int tls_mode = TLS_MODE_DETECT;
64 static int lmf_pthread_key = -1;
65 static int monothread_key = -1;
66 static int monodomain_key = -1;
68 /* Whenever the host is little-endian */
69 static int little_endian;
70 /* Index of ms word/register */
71 static int ls_word_idx;
72 /* Index of ls word/register */
73 static int ms_word_idx;
74 /* Same for offsets */
75 static int ls_word_offset;
76 static int ms_word_offset;
79 * The code generated for sequence points reads from this location, which is
80 * made read-only when single stepping is enabled.
82 static gpointer ss_trigger_page;
84 /* Enabled breakpoints read from this trigger page */
85 static gpointer bp_trigger_page;
88 #define DEBUG(a) if (cfg->verbose_level > 1) a
94 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
96 code = mips_emit_exc_by_name (code, exc_name); \
97 cfg->bb_exit->max_offset += 16; \
101 #define emit_linuxthreads_tls(code,dreg,key) do {\
103 off1 = offsets_from_pthread_key ((key), &off2); \
104 g_assert_not_reached (); \
105 ppc_lwz ((code), (dreg), off1, ppc_r2); \
106 ppc_lwz ((code), (dreg), off2, (dreg)); \
110 #define emit_tls_access(code,dreg,key) do { \
111 switch (tls_mode) { \
112 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
113 default: g_assert_not_reached (); \
117 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
119 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
120 inst->type = STACK_R8; \
122 inst->inst_p0 = (void*)(addr); \
123 mono_bblock_add_inst (cfg->cbb, inst); \
126 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
127 || ((ins)->opcode == OP_ICOMPARE) \
128 || ((ins)->opcode == OP_LCOMPARE)))
129 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
130 || ((ins)->opcode == OP_ICOMPARE_IMM) \
131 || ((ins)->opcode == OP_LCOMPARE_IMM)))
133 #define INS_REWRITE(ins, op, _s1, _s2) do { \
136 ins->opcode = (op); \
141 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
143 ins->opcode = (op); \
145 ins->inst_imm = (_imm); \
149 typedef struct InstList InstList;
167 guint16 vtsize; /* in param area */
170 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
179 gboolean vtype_retaddr;
188 void patch_lui_addiu(guint32 *ip, guint32 val);
189 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
190 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
191 void mips_adjust_stackframe(MonoCompile *cfg);
192 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
193 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
196 /* Not defined in asm/cachectl.h */
197 int cacheflush(char *addr, int nbytes, int cache);
200 mono_arch_flush_icache (guint8 *code, gint size)
202 /* Linux/MIPS specific */
203 cacheflush ((char*)code, size, BCACHE);
207 mono_arch_flush_register_windows (void)
212 mono_arch_is_inst_imm (gint64 imm)
218 mips_emit_exc_by_name(guint8 *code, const char *name)
221 MonoClass *exc_class;
223 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
224 g_assert (exc_class);
226 mips_load_const (code, mips_a0, exc_class->type_token);
227 addr = mono_get_throw_corlib_exception ();
228 mips_call (code, mips_t9, addr);
234 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
236 if (mips_is_imm16 (v))
237 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
239 #if SIZEOF_REGISTER == 8
241 /* v is not a sign-extended 32-bit value */
242 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
243 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
244 mips_dsll (code, dreg, dreg, 16);
245 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
246 mips_dsll (code, dreg, dreg, 16);
247 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
251 if (((guint32)v) & (1 << 15)) {
252 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
255 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
257 if (((guint32)v) & 0xffff)
258 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
264 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
267 if (cfg->arch.long_branch) {
270 /* Invert test and emit branch around jump */
273 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
277 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
281 mips_bltz (code, ins->sreg1, br_offset);
285 mips_blez (code, ins->sreg1, br_offset);
289 mips_bgtz (code, ins->sreg1, br_offset);
293 mips_bgez (code, ins->sreg1, br_offset);
297 g_assert_not_reached ();
299 mono_add_patch_info (cfg, code - cfg->native_code,
300 MONO_PATCH_INFO_BB, ins->inst_true_bb);
301 mips_lui (code, mips_at, mips_zero, 0);
302 mips_addiu (code, mips_at, mips_at, 0);
303 mips_jr (code, mips_at);
307 mono_add_patch_info (cfg, code - cfg->native_code,
308 MONO_PATCH_INFO_BB, ins->inst_true_bb);
311 mips_beq (code, ins->sreg1, ins->sreg2, 0);
315 mips_bne (code, ins->sreg1, ins->sreg2, 0);
319 mips_bgez (code, ins->sreg1, 0);
323 mips_bgtz (code, ins->sreg1, 0);
327 mips_blez (code, ins->sreg1, 0);
331 mips_bltz (code, ins->sreg1, 0);
335 g_assert_not_reached ();
341 /* XXX - big-endian dependent? */
343 patch_lui_addiu(guint32 *ip, guint32 val)
345 guint16 *__lui_addiu = (guint16*)(void *)(ip);
348 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
349 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
352 if (((guint32)(val)) & (1 << 15))
353 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
355 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
356 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
357 mono_arch_flush_icache ((guint8 *)ip, 8);
362 mips_patch (guint32 *code, guint32 target)
365 guint32 op = ins >> 26;
366 guint32 diff, offset;
368 g_assert (trap_target != target);
369 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
371 case 0x00: /* jr ra */
372 if (ins == 0x3e00008)
374 g_assert_not_reached ();
378 g_assert (!(target & 0x03));
379 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
380 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
382 mono_arch_flush_icache ((guint8 *)code, 4);
384 case 0x01: /* BLTZ */
387 case 0x06: /* BLEZ */
388 case 0x07: /* BGTZ */
389 case 0x11: /* bc1t */
390 diff = target - (guint32)(code + 1);
391 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
392 g_assert (!(diff & 0x03));
393 offset = ((gint32)diff) >> 2;
394 if (((int)offset) != ((int)(short)offset))
395 g_assert (((int)offset) == ((int)(short)offset));
396 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
398 mono_arch_flush_icache ((guint8 *)code, 4);
400 case 0x0f: /* LUI / ADDIU pair */
401 g_assert ((code[1] >> 26) == 0x9);
402 patch_lui_addiu (code, target);
403 mono_arch_flush_icache ((guint8 *)code, 8);
407 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
408 g_assert_not_reached ();
414 offsets_from_pthread_key (guint32 key, int *offset2)
418 *offset2 = idx2 * sizeof (gpointer);
419 return 284 + idx1 * sizeof (gpointer);
423 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
426 mono_arch_regname (int reg) {
427 #if _MIPS_SIM == _ABIO32
428 static const char * rnames[] = {
429 "zero", "at", "v0", "v1",
430 "a0", "a1", "a2", "a3",
431 "t0", "t1", "t2", "t3",
432 "t4", "t5", "t6", "t7",
433 "s0", "s1", "s2", "s3",
434 "s4", "s5", "s6", "s7",
435 "t8", "t9", "k0", "k1",
436 "gp", "sp", "fp", "ra"
438 #elif _MIPS_SIM == _ABIN32
439 static const char * rnames[] = {
440 "zero", "at", "v0", "v1",
441 "a0", "a1", "a2", "a3",
442 "a4", "a5", "a6", "a7",
443 "t0", "t1", "t2", "t3",
444 "s0", "s1", "s2", "s3",
445 "s4", "s5", "s6", "s7",
446 "t8", "t9", "k0", "k1",
447 "gp", "sp", "fp", "ra"
450 if (reg >= 0 && reg < 32)
456 mono_arch_fregname (int reg) {
457 static const char * rnames[] = {
458 "f0", "f1", "f2", "f3",
459 "f4", "f5", "f6", "f7",
460 "f8", "f9", "f10", "f11",
461 "f12", "f13", "f14", "f15",
462 "f16", "f17", "f18", "f19",
463 "f20", "f21", "f22", "f23",
464 "f24", "f25", "f26", "f27",
465 "f28", "f29", "f30", "f31"
467 if (reg >= 0 && reg < 32)
472 /* this function overwrites at */
474 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
476 /* XXX write a loop, not an unrolled loop */
478 mips_lw (code, mips_at, sreg, soffset);
479 mips_sw (code, mips_at, dreg, doffset);
488 * mono_arch_get_argument_info:
489 * @csig: a method signature
490 * @param_count: the number of parameters to consider
491 * @arg_info: an array to store the result infos
493 * Gathers information on parameters such as size, alignment and
494 * padding. arg_info should be large enought to hold param_count + 1 entries.
496 * Returns the size of the activation frame.
499 mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
501 int k, frame_size = 0;
502 guint32 size, align, pad;
505 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
506 frame_size += sizeof (gpointer);
510 arg_info [0].offset = offset;
513 frame_size += sizeof (gpointer);
517 arg_info [0].size = frame_size;
519 for (k = 0; k < param_count; k++) {
520 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
522 /* ignore alignment for now */
525 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
526 arg_info [k].pad = pad;
528 arg_info [k + 1].pad = 0;
529 arg_info [k + 1].size = size;
531 arg_info [k + 1].offset = offset;
535 align = MONO_ARCH_FRAME_ALIGNMENT;
536 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
537 arg_info [k].pad = pad;
542 /* The delegate object plus 3 params */
543 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
546 get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
548 guint8 *code, *start;
551 start = code = mono_global_codeman_reserve (16);
553 /* Replace the this argument with the target */
554 mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
555 mips_lw (code, mips_a0, mips_a0, G_STRUCT_OFFSET (MonoDelegate, target));
556 mips_jr (code, mips_temp);
559 g_assert ((code - start) <= 16);
561 mono_arch_flush_icache (start, 16);
565 size = 16 + param_count * 4;
566 start = code = mono_global_codeman_reserve (size);
568 mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
569 /* slide down the arguments */
570 for (i = 0; i < param_count; ++i) {
571 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
573 mips_jr (code, mips_temp);
576 g_assert ((code - start) <= size);
578 mono_arch_flush_icache (start, size);
582 *code_size = code - start;
588 * mono_arch_get_delegate_invoke_impls:
590 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
594 mono_arch_get_delegate_invoke_impls (void)
601 code = get_delegate_invoke_impl (TRUE, 0, &code_len);
602 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
604 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
605 code = get_delegate_invoke_impl (FALSE, i, &code_len);
606 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
613 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
615 guint8 *code, *start;
617 /* FIXME: Support more cases */
618 if (MONO_TYPE_ISSTRUCT (sig->ret))
622 static guint8* cached = NULL;
623 mono_mini_arch_lock ();
625 mono_mini_arch_unlock ();
630 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
632 start = get_delegate_invoke_impl (TRUE, 0, NULL);
634 mono_mini_arch_unlock ();
637 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
640 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
642 for (i = 0; i < sig->param_count; ++i)
643 if (!mono_is_regsize_var (sig->params [i]))
646 mono_mini_arch_lock ();
647 code = cache [sig->param_count];
649 mono_mini_arch_unlock ();
654 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
655 start = mono_aot_get_trampoline (name);
658 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
660 cache [sig->param_count] = start;
661 mono_mini_arch_unlock ();
669 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
672 return (gpointer)regs [mips_a0];
676 * Initialize the cpu to execute managed code.
679 mono_arch_cpu_init (void)
681 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
690 ls_word_offset = ls_word_idx * 4;
691 ms_word_offset = ms_word_idx * 4;
695 * Initialize architecture specific code.
698 mono_arch_init (void)
700 InitializeCriticalSection (&mini_arch_mutex);
702 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
703 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
704 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
708 * Cleanup architecture specific code.
711 mono_arch_cleanup (void)
713 DeleteCriticalSection (&mini_arch_mutex);
717 * This function returns the optimizations supported on this cpu.
720 mono_arch_cpu_optimizations (guint32 *exclude_mask)
724 /* no mips-specific optimizations yet */
730 * This function test for all SIMD functions supported.
732 * Returns a bitmask corresponding to all supported versions.
736 mono_arch_cpu_enumerate_simd_versions (void)
738 /* SIMD is currently unimplemented */
743 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
748 for (i = 0; i < cfg->num_varinfo; i++) {
749 MonoInst *ins = cfg->varinfo [i];
750 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
753 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
756 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
759 /* we can only allocate 32 bit values */
760 if (mono_is_regsize_var (ins->inst_vtype)) {
761 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
762 g_assert (i == vmv->idx);
763 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
771 mono_arch_get_global_int_regs (MonoCompile *cfg)
775 regs = g_list_prepend (regs, (gpointer)mips_s0);
776 regs = g_list_prepend (regs, (gpointer)mips_s1);
777 regs = g_list_prepend (regs, (gpointer)mips_s2);
778 regs = g_list_prepend (regs, (gpointer)mips_s3);
779 regs = g_list_prepend (regs, (gpointer)mips_s4);
780 //regs = g_list_prepend (regs, (gpointer)mips_s5);
781 regs = g_list_prepend (regs, (gpointer)mips_s6);
782 regs = g_list_prepend (regs, (gpointer)mips_s7);
788 * mono_arch_regalloc_cost:
790 * Return the cost, in number of memory references, of the action of
791 * allocating the variable VMV into a register during global register
795 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
802 args_onto_stack (CallInfo *info)
804 g_assert (!info->on_stack);
805 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
806 info->on_stack = TRUE;
807 info->stack_size = MIPS_STACK_PARAM_OFFSET;
810 #if _MIPS_SIM == _ABIO32
812 * O32 calling convention version
816 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
817 /* First, see if we need to drop onto the stack */
818 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
819 args_onto_stack (info);
821 /* Now, place the argument */
822 if (info->on_stack) {
823 ainfo->storage = ArgOnStack;
824 ainfo->reg = mips_sp; /* in the caller */
825 ainfo->offset = info->stack_size;
828 ainfo->storage = ArgInIReg;
829 ainfo->reg = info->gr;
831 info->gr_passed = TRUE;
833 info->stack_size += 4;
837 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
838 /* First, see if we need to drop onto the stack */
839 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
840 args_onto_stack (info);
842 /* Now, place the argument */
843 if (info->on_stack) {
844 g_assert (info->stack_size % 4 == 0);
845 info->stack_size += (info->stack_size % 8);
847 ainfo->storage = ArgOnStack;
848 ainfo->reg = mips_sp; /* in the caller */
849 ainfo->offset = info->stack_size;
852 // info->gr must be a0 or a2
853 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
854 g_assert(info->gr <= MIPS_LAST_ARG_REG);
856 ainfo->storage = ArgInIReg;
857 ainfo->reg = info->gr;
859 info->gr_passed = TRUE;
861 info->stack_size += 8;
865 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
866 /* First, see if we need to drop onto the stack */
867 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
868 args_onto_stack (info);
870 /* Now, place the argument */
871 if (info->on_stack) {
872 ainfo->storage = ArgOnStack;
873 ainfo->reg = mips_sp; /* in the caller */
874 ainfo->offset = info->stack_size;
877 /* Only use FP regs for args if no int args passed yet */
878 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
879 ainfo->storage = ArgInFReg;
880 ainfo->reg = info->fr;
881 /* Even though it's a single-precision float, it takes up two FP regs */
883 /* FP and GP slots do not overlap */
887 /* Passing single-precision float arg in a GP register
888 * such as: func (0, 1.0, 2, 3);
889 * In this case, only one 'gr' register is consumed.
891 ainfo->storage = ArgInIReg;
892 ainfo->reg = info->gr;
895 info->gr_passed = TRUE;
898 info->stack_size += 4;
902 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
903 /* First, see if we need to drop onto the stack */
904 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
905 args_onto_stack (info);
907 /* Now, place the argument */
908 if (info->on_stack) {
909 g_assert(info->stack_size % 4 == 0);
910 info->stack_size += (info->stack_size % 8);
912 ainfo->storage = ArgOnStack;
913 ainfo->reg = mips_sp; /* in the caller */
914 ainfo->offset = info->stack_size;
917 /* Only use FP regs for args if no int args passed yet */
918 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
919 ainfo->storage = ArgInFReg;
920 ainfo->reg = info->fr;
922 /* FP and GP slots do not overlap */
926 // info->gr must be a0 or a2
927 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
928 g_assert(info->gr <= MIPS_LAST_ARG_REG);
930 ainfo->storage = ArgInIReg;
931 ainfo->reg = info->gr;
933 info->gr_passed = TRUE;
936 info->stack_size += 8;
938 #elif _MIPS_SIM == _ABIN32
940 * N32 calling convention version
944 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
945 /* First, see if we need to drop onto the stack */
946 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
947 args_onto_stack (info);
949 /* Now, place the argument */
950 if (info->on_stack) {
951 ainfo->storage = ArgOnStack;
952 ainfo->reg = mips_sp; /* in the caller */
953 ainfo->offset = info->stack_size;
954 info->stack_size += SIZEOF_REGISTER;
957 ainfo->storage = ArgInIReg;
958 ainfo->reg = info->gr;
960 info->gr_passed = TRUE;
965 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
966 /* First, see if we need to drop onto the stack */
967 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
968 args_onto_stack (info);
970 /* Now, place the argument */
971 if (info->on_stack) {
972 g_assert (info->stack_size % 4 == 0);
973 info->stack_size += (info->stack_size % 8);
975 ainfo->storage = ArgOnStack;
976 ainfo->reg = mips_sp; /* in the caller */
977 ainfo->offset = info->stack_size;
978 info->stack_size += SIZEOF_REGISTER;
981 g_assert (info->gr <= MIPS_LAST_ARG_REG);
983 ainfo->storage = ArgInIReg;
984 ainfo->reg = info->gr;
986 info->gr_passed = TRUE;
991 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
992 /* First, see if we need to drop onto the stack */
993 if (!info->on_stack) {
994 if (info->gr > MIPS_LAST_ARG_REG)
995 args_onto_stack (info);
996 else if (info->fr > MIPS_LAST_FPARG_REG)
997 args_onto_stack (info);
1000 /* Now, place the argument */
1001 if (info->on_stack) {
1002 ainfo->storage = ArgOnStack;
1003 ainfo->reg = mips_sp; /* in the caller */
1004 ainfo->offset = info->stack_size;
1005 info->stack_size += FREG_SIZE;
1008 ainfo->storage = ArgInFReg;
1009 ainfo->reg = info->fr;
1011 /* FP and GP slots do not overlap */
1017 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1018 /* First, see if we need to drop onto the stack */
1019 if (!info->on_stack) {
1020 if (info->gr > MIPS_LAST_ARG_REG)
1021 args_onto_stack (info);
1022 else if (info->fr > MIPS_LAST_FPARG_REG)
1023 args_onto_stack (info);
1026 /* Now, place the argument */
1027 if (info->on_stack) {
1028 g_assert(info->stack_size % 4 == 0);
1029 info->stack_size += (info->stack_size % 8);
1031 ainfo->storage = ArgOnStack;
1032 ainfo->reg = mips_sp; /* in the caller */
1033 ainfo->offset = info->stack_size;
1034 info->stack_size += FREG_SIZE;
1037 ainfo->storage = ArgInFReg;
1038 ainfo->reg = info->fr;
1040 /* FP and GP slots do not overlap */
1047 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
1050 int n = sig->hasthis + sig->param_count;
1052 MonoType* simpletype;
1054 gboolean is_pinvoke = sig->pinvoke;
1057 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1059 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1061 cinfo->fr = MIPS_FIRST_FPARG_REG;
1062 cinfo->gr = MIPS_FIRST_ARG_REG;
1063 cinfo->stack_size = 0;
1065 DEBUG(printf("calculate_sizes\n"));
1067 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1071 /* handle returning a struct */
1072 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1073 cinfo->struct_ret = cinfo->gr;
1074 add_int32_arg (cinfo, &cinfo->ret);
1078 add_int32_arg (cinfo, cinfo->args + n);
1083 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1084 * the first argument, allowing 'this' to be always passed in the first arg reg.
1085 * Also do this if the first argument is a reference type, since virtual calls
1086 * are sometimes made using calli without sig->hasthis set, like in the delegate
1089 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
1091 add_int32_arg (cinfo, cinfo->args + n);
1094 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1098 add_int32_arg (cinfo, &cinfo->ret);
1099 cinfo->struct_ret = cinfo->ret.reg;
1103 add_int32_arg (cinfo, cinfo->args + n);
1107 if (cinfo->vtype_retaddr) {
1108 add_int32_arg (cinfo, &cinfo->ret);
1109 cinfo->struct_ret = cinfo->ret.reg;
1114 DEBUG(printf("params: %d\n", sig->param_count));
1115 for (i = pstart; i < sig->param_count; ++i) {
1116 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1117 /* Prevent implicit arguments and sig_cookie from
1118 being passed in registers */
1119 args_onto_stack (cinfo);
1120 /* Emit the signature cookie just before the implicit arguments */
1121 add_int32_arg (cinfo, &cinfo->sig_cookie);
1123 DEBUG(printf("param %d: ", i));
1124 simpletype = mini_type_get_underlying_type (gsctx, sig->params [i]);
1125 switch (simpletype->type) {
1126 case MONO_TYPE_BOOLEAN:
1129 DEBUG(printf("1 byte\n"));
1130 cinfo->args [n].size = 1;
1131 add_int32_arg (cinfo, &cinfo->args[n]);
1134 case MONO_TYPE_CHAR:
1137 DEBUG(printf("2 bytes\n"));
1138 cinfo->args [n].size = 2;
1139 add_int32_arg (cinfo, &cinfo->args[n]);
1144 DEBUG(printf("4 bytes\n"));
1145 cinfo->args [n].size = 4;
1146 add_int32_arg (cinfo, &cinfo->args[n]);
1152 case MONO_TYPE_FNPTR:
1153 case MONO_TYPE_CLASS:
1154 case MONO_TYPE_OBJECT:
1155 case MONO_TYPE_STRING:
1156 case MONO_TYPE_SZARRAY:
1157 case MONO_TYPE_ARRAY:
1158 cinfo->args [n].size = sizeof (gpointer);
1159 add_int32_arg (cinfo, &cinfo->args[n]);
1162 case MONO_TYPE_GENERICINST:
1163 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1164 cinfo->args [n].size = sizeof (gpointer);
1165 add_int32_arg (cinfo, &cinfo->args[n]);
1170 case MONO_TYPE_TYPEDBYREF:
1171 case MONO_TYPE_VALUETYPE: {
1174 int has_offset = FALSE;
1176 gint size, alignment;
1179 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1180 size = sizeof (MonoTypedRef);
1181 alignment = sizeof (gpointer);
1183 klass = mono_class_from_mono_type (sig->params [i]);
1185 size = mono_class_native_size (klass, NULL);
1187 size = mono_class_value_size (klass, NULL);
1188 alignment = mono_class_min_align (klass);
1190 #if MIPS_PASS_STRUCTS_BY_VALUE
1191 /* Need to do alignment if struct contains long or double */
1192 if (alignment > 4) {
1193 /* Drop onto stack *before* looking at
1194 stack_size, if required. */
1195 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1196 args_onto_stack (cinfo);
1197 if (cinfo->stack_size & (alignment - 1)) {
1198 add_int32_arg (cinfo, &dummy_arg);
1200 g_assert (!(cinfo->stack_size & (alignment - 1)));
1204 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1205 mono_class_native_size (sig->params [i]->data.klass, NULL),
1206 cinfo->stack_size, alignment);
1208 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1209 g_assert (cinfo->args [n].size == 0);
1210 g_assert (cinfo->args [n].vtsize == 0);
1211 for (j = 0; j < nwords; ++j) {
1213 add_int32_arg (cinfo, &cinfo->args [n]);
1214 if (cinfo->on_stack)
1217 add_int32_arg (cinfo, &dummy_arg);
1218 if (!has_offset && cinfo->on_stack) {
1219 cinfo->args [n].offset = dummy_arg.offset;
1223 if (cinfo->on_stack)
1224 cinfo->args [n].vtsize += 1;
1226 cinfo->args [n].size += 1;
1228 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1229 cinfo->args [n].storage = ArgStructByVal;
1231 add_int32_arg (cinfo, &cinfo->args[n]);
1232 cinfo->args [n].storage = ArgStructByAddr;
1239 DEBUG(printf("8 bytes\n"));
1240 cinfo->args [n].size = 8;
1241 add_int64_arg (cinfo, &cinfo->args[n]);
1245 DEBUG(printf("R4\n"));
1246 cinfo->args [n].size = 4;
1247 add_float32_arg (cinfo, &cinfo->args[n]);
1251 DEBUG(printf("R8\n"));
1252 cinfo->args [n].size = 8;
1253 add_float64_arg (cinfo, &cinfo->args[n]);
1257 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1261 /* Handle the case where there are no implicit arguments */
1262 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1263 /* Prevent implicit arguments and sig_cookie from
1264 being passed in registers */
1265 args_onto_stack (cinfo);
1266 /* Emit the signature cookie just before the implicit arguments */
1267 add_int32_arg (cinfo, &cinfo->sig_cookie);
1271 simpletype = mini_type_get_underlying_type (gsctx, sig->ret);
1272 switch (simpletype->type) {
1273 case MONO_TYPE_BOOLEAN:
1278 case MONO_TYPE_CHAR:
1284 case MONO_TYPE_FNPTR:
1285 case MONO_TYPE_CLASS:
1286 case MONO_TYPE_OBJECT:
1287 case MONO_TYPE_SZARRAY:
1288 case MONO_TYPE_ARRAY:
1289 case MONO_TYPE_STRING:
1290 cinfo->ret.reg = mips_v0;
1294 cinfo->ret.reg = mips_v0;
1298 cinfo->ret.reg = mips_f0;
1299 cinfo->ret.storage = ArgInFReg;
1301 case MONO_TYPE_GENERICINST:
1302 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1303 cinfo->ret.reg = mips_v0;
1307 case MONO_TYPE_VALUETYPE:
1308 case MONO_TYPE_TYPEDBYREF:
1310 case MONO_TYPE_VOID:
1313 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1317 /* align stack size to 16 */
1318 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1320 cinfo->stack_usage = cinfo->stack_size;
1325 debug_omit_fp (void)
1328 return mono_debug_count ();
1335 * mono_arch_compute_omit_fp:
1337 * Determine whenever the frame pointer can be eliminated.
1340 mono_arch_compute_omit_fp (MonoCompile *cfg)
1342 MonoMethodSignature *sig;
1343 MonoMethodHeader *header;
1347 if (cfg->arch.omit_fp_computed)
1350 header = cfg->header;
1352 sig = mono_method_signature (cfg->method);
1354 if (!cfg->arch.cinfo)
1355 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1356 cinfo = cfg->arch.cinfo;
1359 * FIXME: Remove some of the restrictions.
1361 cfg->arch.omit_fp = TRUE;
1362 cfg->arch.omit_fp_computed = TRUE;
1364 if (cfg->disable_omit_fp)
1365 cfg->arch.omit_fp = FALSE;
1366 if (!debug_omit_fp ())
1367 cfg->arch.omit_fp = FALSE;
1368 if (cfg->method->save_lmf)
1369 cfg->arch.omit_fp = FALSE;
1370 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1371 cfg->arch.omit_fp = FALSE;
1372 if (header->num_clauses)
1373 cfg->arch.omit_fp = FALSE;
1374 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1375 cfg->arch.omit_fp = FALSE;
1376 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1377 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1378 cfg->arch.omit_fp = FALSE;
1380 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1381 * there are stack arguments.
1384 if (cinfo->stack_usage)
1385 cfg->arch.omit_fp = FALSE;
1389 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1390 MonoInst *ins = cfg->varinfo [i];
1393 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1396 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1400 * Set var information according to the calling convention. mips version.
1401 * The locals var stuff should most likely be split in another method.
1404 mono_arch_allocate_vars (MonoCompile *cfg)
1406 MonoMethodSignature *sig;
1407 MonoMethodHeader *header;
1409 int i, offset, size, align, curinst;
1410 int frame_reg = mips_sp;
1411 guint32 iregs_to_save = 0;
1413 guint32 fregs_to_restore;
1417 sig = mono_method_signature (cfg->method);
1419 if (!cfg->arch.cinfo)
1420 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1421 cinfo = cfg->arch.cinfo;
1423 mono_arch_compute_omit_fp (cfg);
1425 /* spill down, we'll fix it in a separate pass */
1426 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1428 /* allow room for the vararg method args: void* and long/double */
1429 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1430 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1432 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1433 * call convs needs to be handled this way.
1435 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1436 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1438 /* gtk-sharp and other broken code will dllimport vararg functions even with
1439 * non-varargs signatures. Since there is little hope people will get this right
1440 * we assume they won't.
1442 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1443 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1445 /* a0-a3 always present */
1446 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1448 header = cfg->header;
1450 if (cfg->arch.omit_fp)
1451 frame_reg = mips_sp;
1453 frame_reg = mips_fp;
1454 cfg->frame_reg = frame_reg;
1455 if (frame_reg != mips_sp) {
1456 cfg->used_int_regs |= 1 << frame_reg;
1461 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1462 /* FIXME: handle long and FP values */
1463 switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
1464 case MONO_TYPE_VOID:
1468 cfg->ret->opcode = OP_REGVAR;
1469 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1472 cfg->ret->opcode = OP_REGVAR;
1473 cfg->ret->inst_c0 = mips_v0;
1477 /* Space for outgoing parameters, including a0-a3 */
1478 offset += cfg->param_area;
1480 /* allow room to save the return value (if it's a struct) */
1481 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1484 /* Now handle the local variables */
1486 curinst = cfg->locals_start;
1487 for (i = curinst; i < cfg->num_varinfo; ++i) {
1488 inst = cfg->varinfo [i];
1489 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1492 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1493 * pinvoke wrappers when they call functions returning structure
1495 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1496 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1498 size = mono_type_size (inst->inst_vtype, &align);
1500 offset += align - 1;
1501 offset &= ~(align - 1);
1502 inst->inst_offset = offset;
1503 inst->opcode = OP_REGOFFSET;
1504 inst->inst_basereg = frame_reg;
1506 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1509 /* Space for LMF (if needed) */
1510 if (cfg->method->save_lmf) {
1511 /* align the offset to 16 bytes */
1512 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1513 cfg->arch.lmf_offset = offset;
1514 offset += sizeof (MonoLMF);
1517 if (sig->call_convention == MONO_CALL_VARARG) {
1521 /* Allocate a local slot to hold the sig cookie address */
1522 offset += align - 1;
1523 offset &= ~(align - 1);
1524 cfg->sig_cookie = offset;
1528 offset += SIZEOF_REGISTER - 1;
1529 offset &= ~(SIZEOF_REGISTER - 1);
1531 /* Space for saved registers */
1532 cfg->arch.iregs_offset = offset;
1533 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1534 if (iregs_to_save) {
1535 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1536 if (iregs_to_save & (1 << i)) {
1537 offset += SIZEOF_REGISTER;
1542 /* saved float registers */
1544 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1545 if (fregs_to_restore) {
1546 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1547 if (fregs_to_restore & (1 << i)) {
1548 offset += sizeof(double);
1554 #if _MIPS_SIM == _ABIO32
1555 /* Now add space for saving the ra */
1556 offset += SIZEOF_VOID_P;
1559 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1560 cfg->stack_offset = offset;
1561 cfg->arch.local_alloc_offset = cfg->stack_offset;
1565 * Now allocate stack slots for the int arg regs (a0 - a3)
1566 * On MIPS o32, these are just above the incoming stack pointer
1567 * Even if the arg has been assigned to a regvar, it gets a stack slot
1570 /* Return struct-by-value results in a hidden first argument */
1571 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1572 cfg->vret_addr->opcode = OP_REGOFFSET;
1573 cfg->vret_addr->inst_c0 = mips_a0;
1574 cfg->vret_addr->inst_offset = offset;
1575 cfg->vret_addr->inst_basereg = frame_reg;
1576 offset += SIZEOF_REGISTER;
1579 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1580 inst = cfg->args [i];
1581 if (inst->opcode != OP_REGVAR) {
1584 if (sig->hasthis && (i == 0))
1585 arg_type = &mono_defaults.object_class->byval_arg;
1587 arg_type = sig->params [i - sig->hasthis];
1589 inst->opcode = OP_REGOFFSET;
1590 size = mono_type_size (arg_type, &align);
1592 if (size < SIZEOF_REGISTER) {
1593 size = SIZEOF_REGISTER;
1594 align = SIZEOF_REGISTER;
1596 inst->inst_basereg = frame_reg;
1597 offset = (offset + align - 1) & ~(align - 1);
1598 inst->inst_offset = offset;
1600 if (cfg->verbose_level > 1)
1601 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1604 #if _MIPS_SIM == _ABIO32
1605 /* o32: Even a0-a3 get stack slots */
1606 size = SIZEOF_REGISTER;
1607 align = SIZEOF_REGISTER;
1608 inst->inst_basereg = frame_reg;
1609 offset = (offset + align - 1) & ~(align - 1);
1610 inst->inst_offset = offset;
1612 if (cfg->verbose_level > 1)
1613 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1617 #if _MIPS_SIM == _ABIN32
1618 /* Now add space for saving the ra */
1619 offset += SIZEOF_VOID_P;
1622 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1623 cfg->stack_offset = offset;
1624 cfg->arch.local_alloc_offset = cfg->stack_offset;
1629 mono_arch_create_vars (MonoCompile *cfg)
1631 MonoMethodSignature *sig;
1633 sig = mono_method_signature (cfg->method);
1635 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1636 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1637 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1638 printf ("vret_addr = ");
1639 mono_print_ins (cfg->vret_addr);
1644 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1645 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1649 * take the arguments and generate the arch-specific
1650 * instructions to properly call the function in call.
1651 * This includes pushing, moving arguments to the right register
1653 * Issue: who does the spilling if needed, and when?
1656 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1658 MonoMethodSignature *tmp_sig;
1661 if (call->tail_call)
1664 /* FIXME: Add support for signature tokens to AOT */
1665 cfg->disable_aot = TRUE;
1668 * mono_ArgIterator_Setup assumes the signature cookie is
1669 * passed first and all the arguments which were before it are
1670 * passed on the stack after the signature. So compensate by
1671 * passing a different signature.
1673 tmp_sig = mono_metadata_signature_dup (call->signature);
1674 tmp_sig->param_count -= call->signature->sentinelpos;
1675 tmp_sig->sentinelpos = 0;
1676 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1678 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1679 sig_arg->dreg = mono_alloc_ireg (cfg);
1680 sig_arg->inst_p0 = tmp_sig;
1681 MONO_ADD_INS (cfg->cbb, sig_arg);
1683 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1687 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1690 MonoMethodSignature *sig;
1695 sig = call->signature;
1696 n = sig->param_count + sig->hasthis;
1698 cinfo = get_call_info (NULL, cfg->mempool, sig);
1699 if (cinfo->struct_ret)
1700 call->used_iregs |= 1 << cinfo->struct_ret;
1702 for (i = 0; i < n; ++i) {
1703 ArgInfo *ainfo = cinfo->args + i;
1706 if (i >= sig->hasthis)
1707 t = sig->params [i - sig->hasthis];
1709 t = &mono_defaults.int_class->byval_arg;
1710 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1712 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1713 /* Emit the signature cookie just before the implicit arguments */
1714 emit_sig_cookie (cfg, call, cinfo);
1717 if (is_virtual && i == 0) {
1718 /* the argument will be attached to the call instrucion */
1719 in = call->args [i];
1720 call->used_iregs |= 1 << ainfo->reg;
1723 in = call->args [i];
1724 if (ainfo->storage == ArgInIReg) {
1725 #if SIZEOF_REGISTER == 4
1726 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1727 MONO_INST_NEW (cfg, ins, OP_MOVE);
1728 ins->dreg = mono_alloc_ireg (cfg);
1729 ins->sreg1 = in->dreg + 1;
1730 MONO_ADD_INS (cfg->cbb, ins);
1731 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1733 MONO_INST_NEW (cfg, ins, OP_MOVE);
1734 ins->dreg = mono_alloc_ireg (cfg);
1735 ins->sreg1 = in->dreg + 2;
1736 MONO_ADD_INS (cfg->cbb, ins);
1737 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1740 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1743 #if PROMOTE_R4_TO_R8
1744 /* ??? - convert to single first? */
1745 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1746 ins->dreg = mono_alloc_freg (cfg);
1747 ins->sreg1 = in->dreg;
1748 MONO_ADD_INS (cfg->cbb, ins);
1753 /* trying to load float value into int registers */
1754 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1755 ins->dreg = mono_alloc_ireg (cfg);
1757 MONO_ADD_INS (cfg->cbb, ins);
1758 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1759 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1760 /* trying to load float value into int registers */
1761 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1762 ins->dreg = mono_alloc_ireg (cfg);
1763 ins->sreg1 = in->dreg;
1764 MONO_ADD_INS (cfg->cbb, ins);
1765 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1767 MONO_INST_NEW (cfg, ins, OP_MOVE);
1768 ins->dreg = mono_alloc_ireg (cfg);
1769 ins->sreg1 = in->dreg;
1770 MONO_ADD_INS (cfg->cbb, ins);
1771 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1773 } else if (ainfo->storage == ArgStructByAddr) {
1774 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1775 ins->opcode = OP_OUTARG_VT;
1776 ins->sreg1 = in->dreg;
1777 ins->klass = in->klass;
1778 ins->inst_p0 = call;
1779 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1780 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1781 MONO_ADD_INS (cfg->cbb, ins);
1782 } else if (ainfo->storage == ArgStructByVal) {
1783 /* this is further handled in mono_arch_emit_outarg_vt () */
1784 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1785 ins->opcode = OP_OUTARG_VT;
1786 ins->sreg1 = in->dreg;
1787 ins->klass = in->klass;
1788 ins->inst_p0 = call;
1789 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1790 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1791 MONO_ADD_INS (cfg->cbb, ins);
1792 } else if (ainfo->storage == ArgOnStack) {
1793 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1794 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1795 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1796 if (t->type == MONO_TYPE_R8)
1797 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1799 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1801 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1803 } else if (ainfo->storage == ArgInFReg) {
1804 if (t->type == MONO_TYPE_VALUETYPE) {
1805 /* this is further handled in mono_arch_emit_outarg_vt () */
1806 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1807 ins->opcode = OP_OUTARG_VT;
1808 ins->sreg1 = in->dreg;
1809 ins->klass = in->klass;
1810 ins->inst_p0 = call;
1811 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1812 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1813 MONO_ADD_INS (cfg->cbb, ins);
1815 cfg->flags |= MONO_CFG_HAS_FPOUT;
1817 int dreg = mono_alloc_freg (cfg);
1819 if (ainfo->size == 4) {
1820 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1822 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1824 ins->sreg1 = in->dreg;
1825 MONO_ADD_INS (cfg->cbb, ins);
1828 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1829 cfg->flags |= MONO_CFG_HAS_FPOUT;
1832 g_assert_not_reached ();
1836 /* Handle the case where there are no implicit arguments */
1837 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1838 emit_sig_cookie (cfg, call, cinfo);
1840 if (cinfo->struct_ret) {
1843 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1844 vtarg->sreg1 = call->vret_var->dreg;
1845 vtarg->dreg = mono_alloc_preg (cfg);
1846 MONO_ADD_INS (cfg->cbb, vtarg);
1848 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1852 * Reverse the call->out_args list.
1855 MonoInst *prev = NULL, *list = call->out_args, *next;
1862 call->out_args = prev;
1865 call->stack_usage = cinfo->stack_usage;
1866 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1867 #if _MIPS_SIM == _ABIO32
1868 /* a0-a3 always present */
1869 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1871 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1872 cfg->flags |= MONO_CFG_HAS_CALLS;
1874 * should set more info in call, such as the stack space
1875 * used by the args that needs to be added back to esp
1880 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1882 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1883 ArgInfo *ainfo = ins->inst_p1;
1884 int ovf_size = ainfo->vtsize;
1885 int doffset = ainfo->offset;
1886 int i, soffset, dreg;
1888 if (ainfo->storage == ArgStructByVal) {
1890 if (cfg->verbose_level > 0) {
1891 char* nm = mono_method_full_name (cfg->method, TRUE);
1892 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1893 nm, doffset, ainfo->size, ovf_size);
1899 for (i = 0; i < ainfo->size; ++i) {
1900 dreg = mono_alloc_ireg (cfg);
1901 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1902 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1903 soffset += SIZEOF_REGISTER;
1905 if (ovf_size != 0) {
1906 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1908 } else if (ainfo->storage == ArgInFReg) {
1909 int tmpr = mono_alloc_freg (cfg);
1911 if (ainfo->size == 4)
1912 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1914 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1915 dreg = mono_alloc_freg (cfg);
1916 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1917 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1919 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1923 /* FIXME: alignment? */
1924 if (call->signature->pinvoke) {
1925 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1926 vtcopy->backend.is_pinvoke = 1;
1928 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1931 g_assert (ovf_size > 0);
1933 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1934 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1937 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1939 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1944 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1946 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1947 mono_method_signature (method)->ret);
1950 #if (SIZEOF_REGISTER == 4)
1951 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1954 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1955 ins->sreg1 = val->dreg + 1;
1956 ins->sreg2 = val->dreg + 2;
1957 MONO_ADD_INS (cfg->cbb, ins);
1961 if (ret->type == MONO_TYPE_R8) {
1962 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1965 if (ret->type == MONO_TYPE_R4) {
1966 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1970 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1974 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1976 MonoInst *ins, *n, *last_ins = NULL;
1978 if (cfg->verbose_level > 2)
1979 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1982 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1983 if (cfg->verbose_level > 2)
1984 mono_print_ins_index (0, ins);
1986 switch (ins->opcode) {
1988 case OP_LOAD_MEMBASE:
1989 case OP_LOADI4_MEMBASE:
1991 * OP_IADD reg2, reg1, const1
1992 * OP_LOAD_MEMBASE const2(reg2), reg3
1994 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1996 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)){
1997 int const1 = last_ins->inst_imm;
1998 int const2 = ins->inst_offset;
2000 if (mips_is_imm16 (const1 + const2)) {
2001 ins->inst_basereg = last_ins->sreg1;
2002 ins->inst_offset = const1 + const2;
2012 bb->last_ins = last_ins;
2016 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2018 MonoInst *ins, *n, *last_ins = NULL;
2021 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2022 MonoInst *last_ins = ins->prev;
2024 switch (ins->opcode) {
2026 /* remove unnecessary multiplication with 1 */
2027 if (ins->inst_imm == 1) {
2028 if (ins->dreg != ins->sreg1) {
2029 ins->opcode = OP_MOVE;
2031 MONO_DELETE_INS (bb, ins);
2035 int power2 = mono_is_power_of_two (ins->inst_imm);
2037 ins->opcode = OP_SHL_IMM;
2038 ins->inst_imm = power2;
2042 case OP_LOAD_MEMBASE:
2043 case OP_LOADI4_MEMBASE:
2045 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2046 * OP_LOAD_MEMBASE offset(basereg), reg
2048 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2049 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2050 ins->inst_basereg == last_ins->inst_destbasereg &&
2051 ins->inst_offset == last_ins->inst_offset) {
2052 if (ins->dreg == last_ins->sreg1) {
2053 MONO_DELETE_INS (bb, ins);
2056 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2057 ins->opcode = OP_MOVE;
2058 ins->sreg1 = last_ins->sreg1;
2063 * Note: reg1 must be different from the basereg in the second load
2064 * OP_LOAD_MEMBASE offset(basereg), reg1
2065 * OP_LOAD_MEMBASE offset(basereg), reg2
2067 * OP_LOAD_MEMBASE offset(basereg), reg1
2068 * OP_MOVE reg1, reg2
2070 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2071 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2072 ins->inst_basereg != last_ins->dreg &&
2073 ins->inst_basereg == last_ins->inst_basereg &&
2074 ins->inst_offset == last_ins->inst_offset) {
2076 if (ins->dreg == last_ins->dreg) {
2077 MONO_DELETE_INS (bb, ins);
2080 ins->opcode = OP_MOVE;
2081 ins->sreg1 = last_ins->dreg;
2084 //g_assert_not_reached ();
2089 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2090 * OP_LOAD_MEMBASE offset(basereg), reg
2092 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2093 * OP_ICONST reg, imm
2095 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2096 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2097 ins->inst_basereg == last_ins->inst_destbasereg &&
2098 ins->inst_offset == last_ins->inst_offset) {
2099 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2100 ins->opcode = OP_ICONST;
2101 ins->inst_c0 = last_ins->inst_imm;
2102 g_assert_not_reached (); // check this rule
2107 case OP_LOADU1_MEMBASE:
2108 case OP_LOADI1_MEMBASE:
2109 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2110 ins->inst_basereg == last_ins->inst_destbasereg &&
2111 ins->inst_offset == last_ins->inst_offset) {
2112 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2113 ins->sreg1 = last_ins->sreg1;
2116 case OP_LOADU2_MEMBASE:
2117 case OP_LOADI2_MEMBASE:
2118 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2119 ins->inst_basereg == last_ins->inst_destbasereg &&
2120 ins->inst_offset == last_ins->inst_offset) {
2121 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2122 ins->sreg1 = last_ins->sreg1;
2125 case OP_ICONV_TO_I4:
2126 case OP_ICONV_TO_U4:
2128 ins->opcode = OP_MOVE;
2132 if (ins->dreg == ins->sreg1) {
2133 MONO_DELETE_INS (bb, ins);
2137 * OP_MOVE sreg, dreg
2138 * OP_MOVE dreg, sreg
2140 if (last_ins && last_ins->opcode == OP_MOVE &&
2141 ins->sreg1 == last_ins->dreg &&
2142 ins->dreg == last_ins->sreg1) {
2143 MONO_DELETE_INS (bb, ins);
2151 bb->last_ins = last_ins;
2155 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2163 switch (ins->opcode) {
2166 case OP_LCOMPARE_IMM:
2167 mono_print_ins (ins);
2168 g_assert_not_reached ();
2171 tmp1 = mono_alloc_ireg (cfg);
2172 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2173 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2174 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2175 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2180 tmp1 = mono_alloc_ireg (cfg);
2181 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2182 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2183 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2184 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2189 tmp1 = mono_alloc_ireg (cfg);
2190 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2191 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2192 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2193 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2198 tmp1 = mono_alloc_ireg (cfg);
2199 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2200 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2201 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2202 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2214 mono_print_ins (ins);
2215 g_assert_not_reached ();
2218 tmp1 = mono_alloc_ireg (cfg);
2219 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2220 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2221 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2222 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2230 case OP_LCONV_TO_I1:
2231 case OP_LCONV_TO_I2:
2232 case OP_LCONV_TO_I4:
2233 case OP_LCONV_TO_I8:
2234 case OP_LCONV_TO_R4:
2235 case OP_LCONV_TO_R8:
2236 case OP_LCONV_TO_U4:
2237 case OP_LCONV_TO_U8:
2238 case OP_LCONV_TO_U2:
2239 case OP_LCONV_TO_U1:
2241 case OP_LCONV_TO_OVF_I:
2242 case OP_LCONV_TO_OVF_U:
2244 mono_print_ins (ins);
2245 g_assert_not_reached ();
2248 tmp1 = mono_alloc_ireg (cfg);
2249 tmp2 = mono_alloc_ireg (cfg);
2250 tmp3 = mono_alloc_ireg (cfg);
2251 tmp4 = mono_alloc_ireg (cfg);
2252 tmp5 = mono_alloc_ireg (cfg);
2254 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2256 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2257 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2259 /* add the high 32-bits, and add in the carry from the low 32-bits */
2260 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2261 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2263 /* Overflow happens if
2264 * neg + neg = pos or
2266 * XOR of the high bits returns 0 if the signs match
2267 * XOR of that with the high bit of the result return 1 if overflow.
2270 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2271 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2273 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2274 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2275 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2277 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2278 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2279 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2281 /* Now, if (tmp4 == 0) then overflow */
2282 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2286 case OP_LADD_OVF_UN:
2287 tmp1 = mono_alloc_ireg (cfg);
2288 tmp2 = mono_alloc_ireg (cfg);
2290 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2291 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2292 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2293 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2294 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2295 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2300 case OP_LMUL_OVF_UN:
2301 mono_print_ins (ins);
2302 g_assert_not_reached ();
2305 tmp1 = mono_alloc_ireg (cfg);
2306 tmp2 = mono_alloc_ireg (cfg);
2307 tmp3 = mono_alloc_ireg (cfg);
2308 tmp4 = mono_alloc_ireg (cfg);
2309 tmp5 = mono_alloc_ireg (cfg);
2311 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2313 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2314 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2315 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2317 /* Overflow happens if
2318 * neg - pos = pos or
2320 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2322 * tmp1 = (lhs ^ rhs)
2323 * tmp2 = (lhs ^ result)
2324 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2327 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2328 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2329 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2330 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2332 /* Now, if (tmp4 == 1) then overflow */
2333 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2337 case OP_LSUB_OVF_UN:
2338 tmp1 = mono_alloc_ireg (cfg);
2339 tmp2 = mono_alloc_ireg (cfg);
2341 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2342 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2343 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2344 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2346 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2347 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2351 case OP_LCONV_TO_OVF_I1_UN:
2352 case OP_LCONV_TO_OVF_I2_UN:
2353 case OP_LCONV_TO_OVF_I4_UN:
2354 case OP_LCONV_TO_OVF_I8_UN:
2355 case OP_LCONV_TO_OVF_U1_UN:
2356 case OP_LCONV_TO_OVF_U2_UN:
2357 case OP_LCONV_TO_OVF_U4_UN:
2358 case OP_LCONV_TO_OVF_U8_UN:
2359 case OP_LCONV_TO_OVF_I_UN:
2360 case OP_LCONV_TO_OVF_U_UN:
2361 case OP_LCONV_TO_OVF_I1:
2362 case OP_LCONV_TO_OVF_U1:
2363 case OP_LCONV_TO_OVF_I2:
2364 case OP_LCONV_TO_OVF_U2:
2365 case OP_LCONV_TO_OVF_I4:
2366 case OP_LCONV_TO_OVF_U4:
2367 case OP_LCONV_TO_OVF_I8:
2368 case OP_LCONV_TO_OVF_U8:
2376 case OP_LCONV_TO_R_UN:
2382 case OP_LSHR_UN_IMM:
2384 case OP_LDIV_UN_IMM:
2386 case OP_LREM_UN_IMM:
2397 mono_print_ins (ins);
2398 g_assert_not_reached ();
2400 case OP_LCONV_TO_R8_2:
2401 case OP_LCONV_TO_R4_2:
2402 case OP_LCONV_TO_R_UN_2:
2404 case OP_LCONV_TO_OVF_I4_2:
2405 tmp1 = mono_alloc_ireg (cfg);
2407 /* Overflows if reg2 != sign extension of reg1 */
2408 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2409 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2410 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2418 mono_print_ins (ins);
2419 g_assert_not_reached ();
2427 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2435 switch (ins->opcode) {
2437 tmp1 = mono_alloc_ireg (cfg);
2438 tmp2 = mono_alloc_ireg (cfg);
2439 tmp3 = mono_alloc_ireg (cfg);
2440 tmp4 = mono_alloc_ireg (cfg);
2441 tmp5 = mono_alloc_ireg (cfg);
2443 /* add the operands */
2445 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2447 /* Overflow happens if
2448 * neg + neg = pos or
2451 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2452 * XOR of the high bit returns 0 if the signs match
2453 * XOR of that with the high bit of the result return 1 if overflow.
2456 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2457 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2459 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2460 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2461 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2463 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2464 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2466 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2468 /* Now, if (tmp5 == 0) then overflow */
2469 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2470 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2471 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2475 case OP_IADD_OVF_UN:
2476 tmp1 = mono_alloc_ireg (cfg);
2478 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2479 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2480 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2481 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2482 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2487 tmp1 = mono_alloc_ireg (cfg);
2488 tmp2 = mono_alloc_ireg (cfg);
2489 tmp3 = mono_alloc_ireg (cfg);
2490 tmp4 = mono_alloc_ireg (cfg);
2491 tmp5 = mono_alloc_ireg (cfg);
2493 /* add the operands */
2495 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2497 /* Overflow happens if
2498 * neg - pos = pos or
2500 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2502 * tmp1 = (lhs ^ rhs)
2503 * tmp2 = (lhs ^ result)
2504 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2507 /* tmp3 = 1 if the signs of the two inputs differ */
2508 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2509 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2510 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2511 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2512 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2514 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2515 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2516 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2520 case OP_ISUB_OVF_UN:
2521 tmp1 = mono_alloc_ireg (cfg);
2523 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2524 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2525 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2526 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2527 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2534 map_to_reg_reg_op (int op)
2543 case OP_COMPARE_IMM:
2545 case OP_ICOMPARE_IMM:
2547 case OP_LCOMPARE_IMM:
2563 case OP_LOAD_MEMBASE:
2564 return OP_LOAD_MEMINDEX;
2565 case OP_LOADI4_MEMBASE:
2566 return OP_LOADI4_MEMINDEX;
2567 case OP_LOADU4_MEMBASE:
2568 return OP_LOADU4_MEMINDEX;
2569 case OP_LOADU1_MEMBASE:
2570 return OP_LOADU1_MEMINDEX;
2571 case OP_LOADI2_MEMBASE:
2572 return OP_LOADI2_MEMINDEX;
2573 case OP_LOADU2_MEMBASE:
2574 return OP_LOADU2_MEMINDEX;
2575 case OP_LOADI1_MEMBASE:
2576 return OP_LOADI1_MEMINDEX;
2577 case OP_LOADR4_MEMBASE:
2578 return OP_LOADR4_MEMINDEX;
2579 case OP_LOADR8_MEMBASE:
2580 return OP_LOADR8_MEMINDEX;
2581 case OP_STOREI1_MEMBASE_REG:
2582 return OP_STOREI1_MEMINDEX;
2583 case OP_STOREI2_MEMBASE_REG:
2584 return OP_STOREI2_MEMINDEX;
2585 case OP_STOREI4_MEMBASE_REG:
2586 return OP_STOREI4_MEMINDEX;
2587 case OP_STORE_MEMBASE_REG:
2588 return OP_STORE_MEMINDEX;
2589 case OP_STORER4_MEMBASE_REG:
2590 return OP_STORER4_MEMINDEX;
2591 case OP_STORER8_MEMBASE_REG:
2592 return OP_STORER8_MEMINDEX;
2593 case OP_STORE_MEMBASE_IMM:
2594 return OP_STORE_MEMBASE_REG;
2595 case OP_STOREI1_MEMBASE_IMM:
2596 return OP_STOREI1_MEMBASE_REG;
2597 case OP_STOREI2_MEMBASE_IMM:
2598 return OP_STOREI2_MEMBASE_REG;
2599 case OP_STOREI4_MEMBASE_IMM:
2600 return OP_STOREI4_MEMBASE_REG;
2601 case OP_STOREI8_MEMBASE_IMM:
2602 return OP_STOREI8_MEMBASE_REG;
2604 return mono_op_imm_to_op (op);
2608 map_to_mips_op (int op)
2612 return OP_MIPS_FBEQ;
2614 return OP_MIPS_FBGE;
2616 return OP_MIPS_FBGT;
2618 return OP_MIPS_FBLE;
2620 return OP_MIPS_FBLT;
2622 return OP_MIPS_FBNE;
2624 return OP_MIPS_FBGE_UN;
2626 return OP_MIPS_FBGT_UN;
2628 return OP_MIPS_FBLE_UN;
2630 return OP_MIPS_FBLT_UN;
2638 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2639 g_assert_not_reached ();
2643 #define NEW_INS(cfg,after,dest,op) do { \
2644 MONO_INST_NEW((cfg), (dest), (op)); \
2645 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2648 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2650 MONO_INST_NEW(cfg, temp, (op)); \
2651 mono_bblock_insert_after_ins (bb, (pos), temp); \
2652 temp->dreg = (_dreg); \
2653 temp->sreg1 = (_sreg1); \
2654 temp->sreg2 = (_sreg2); \
2658 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2660 MONO_INST_NEW(cfg, temp, (op)); \
2661 mono_bblock_insert_after_ins (bb, (pos), temp); \
2662 temp->dreg = (_dreg); \
2663 temp->sreg1 = (_sreg1); \
2664 temp->inst_c0 = (_imm); \
2669 * Remove from the instruction list the instructions that can't be
2670 * represented with very simple instructions with no register
2674 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2676 MonoInst *ins, *next, *temp, *last_ins = NULL;
2680 if (cfg->verbose_level > 2) {
2683 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2684 MONO_BB_FOR_EACH_INS (bb, ins) {
2685 mono_print_ins_index (idx++, ins);
2691 MONO_BB_FOR_EACH_INS (bb, ins) {
2693 switch (ins->opcode) {
2698 /* Branch opts can eliminate the branch */
2699 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2705 case OP_COMPARE_IMM:
2706 case OP_ICOMPARE_IMM:
2707 case OP_LCOMPARE_IMM:
2709 /* Branch opts can eliminate the branch */
2710 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2714 if (ins->inst_imm) {
2715 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2716 temp->inst_c0 = ins->inst_imm;
2717 temp->dreg = mono_alloc_ireg (cfg);
2718 ins->sreg2 = temp->dreg;
2722 ins->sreg2 = mips_zero;
2724 if (ins->opcode == OP_COMPARE_IMM)
2725 ins->opcode = OP_COMPARE;
2726 else if (ins->opcode == OP_ICOMPARE_IMM)
2727 ins->opcode = OP_ICOMPARE;
2728 else if (ins->opcode == OP_LCOMPARE_IMM)
2729 ins->opcode = OP_LCOMPARE;
2732 case OP_IDIV_UN_IMM:
2735 case OP_IREM_UN_IMM:
2736 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2737 temp->inst_c0 = ins->inst_imm;
2738 temp->dreg = mono_alloc_ireg (cfg);
2739 ins->sreg2 = temp->dreg;
2740 if (ins->opcode == OP_IDIV_IMM)
2741 ins->opcode = OP_IDIV;
2742 else if (ins->opcode == OP_IREM_IMM)
2743 ins->opcode = OP_IREM;
2744 else if (ins->opcode == OP_IDIV_UN_IMM)
2745 ins->opcode = OP_IDIV_UN;
2746 else if (ins->opcode == OP_IREM_UN_IMM)
2747 ins->opcode = OP_IREM_UN;
2749 /* handle rem separately */
2756 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2757 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2758 temp->inst_c0 = ins->inst_imm;
2759 temp->dreg = mono_alloc_ireg (cfg);
2760 ins->sreg2 = temp->dreg;
2761 ins->opcode = map_to_reg_reg_op (ins->opcode);
2771 /* unsigned 16 bit immediate */
2772 if (ins->inst_imm & 0xffff0000) {
2773 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2774 temp->inst_c0 = ins->inst_imm;
2775 temp->dreg = mono_alloc_ireg (cfg);
2776 ins->sreg2 = temp->dreg;
2777 ins->opcode = map_to_reg_reg_op (ins->opcode);
2784 /* signed 16 bit immediate */
2785 if (!mips_is_imm16 (ins->inst_imm)) {
2786 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2787 temp->inst_c0 = ins->inst_imm;
2788 temp->dreg = mono_alloc_ireg (cfg);
2789 ins->sreg2 = temp->dreg;
2790 ins->opcode = map_to_reg_reg_op (ins->opcode);
2796 if (!mips_is_imm16 (-ins->inst_imm)) {
2797 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2798 temp->inst_c0 = ins->inst_imm;
2799 temp->dreg = mono_alloc_ireg (cfg);
2800 ins->sreg2 = temp->dreg;
2801 ins->opcode = map_to_reg_reg_op (ins->opcode);
2807 if (ins->inst_imm == 1) {
2808 ins->opcode = OP_MOVE;
2811 if (ins->inst_imm == 0) {
2812 ins->opcode = OP_ICONST;
2816 imm = mono_is_power_of_two (ins->inst_imm);
2818 ins->opcode = OP_SHL_IMM;
2819 ins->inst_imm = imm;
2822 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2823 temp->inst_c0 = ins->inst_imm;
2824 temp->dreg = mono_alloc_ireg (cfg);
2825 ins->sreg2 = temp->dreg;
2826 ins->opcode = map_to_reg_reg_op (ins->opcode);
2829 case OP_LOCALLOC_IMM:
2830 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2831 temp->inst_c0 = ins->inst_imm;
2832 temp->dreg = mono_alloc_ireg (cfg);
2833 ins->sreg1 = temp->dreg;
2834 ins->opcode = OP_LOCALLOC;
2837 case OP_LOADR4_MEMBASE:
2838 case OP_STORER4_MEMBASE_REG:
2839 /* we can do two things: load the immed in a register
2840 * and use an indexed load, or see if the immed can be
2841 * represented as an ad_imm + a load with a smaller offset
2842 * that fits. We just do the first for now, optimize later.
2844 if (mips_is_imm16 (ins->inst_offset))
2846 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2847 temp->inst_c0 = ins->inst_offset;
2848 temp->dreg = mono_alloc_ireg (cfg);
2849 ins->sreg2 = temp->dreg;
2850 ins->opcode = map_to_reg_reg_op (ins->opcode);
2853 case OP_STORE_MEMBASE_IMM:
2854 case OP_STOREI1_MEMBASE_IMM:
2855 case OP_STOREI2_MEMBASE_IMM:
2856 case OP_STOREI4_MEMBASE_IMM:
2857 case OP_STOREI8_MEMBASE_IMM:
2858 if (!ins->inst_imm) {
2859 ins->sreg1 = mips_zero;
2860 ins->opcode = map_to_reg_reg_op (ins->opcode);
2863 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2864 temp->inst_c0 = ins->inst_imm;
2865 temp->dreg = mono_alloc_ireg (cfg);
2866 ins->sreg1 = temp->dreg;
2867 ins->opcode = map_to_reg_reg_op (ins->opcode);
2869 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2875 /* Branch opts can eliminate the branch */
2876 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2883 * remap compare/branch and compare/set
2884 * to MIPS specific opcodes.
2886 next->opcode = map_to_mips_op (next->opcode);
2887 next->sreg1 = ins->sreg1;
2888 next->sreg2 = ins->sreg2;
2895 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2896 temp->inst_c0 = (guint32)ins->inst_p0;
2897 temp->dreg = mono_alloc_ireg (cfg);
2898 ins->inst_basereg = temp->dreg;
2899 ins->inst_offset = 0;
2900 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2902 /* make it handle the possibly big ins->inst_offset
2903 * later optimize to use lis + load_membase
2908 g_assert (ins_is_compare(last_ins));
2909 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2910 NULLIFY_INS(last_ins);
2914 g_assert (ins_is_compare(last_ins));
2915 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2916 NULLIFY_INS(last_ins);
2920 g_assert (ins_is_compare(last_ins));
2921 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2922 last_ins->dreg = mono_alloc_ireg (cfg);
2923 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2927 g_assert (ins_is_compare(last_ins));
2928 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2929 last_ins->dreg = mono_alloc_ireg (cfg);
2930 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2934 g_assert (ins_is_compare(last_ins));
2935 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2936 last_ins->dreg = mono_alloc_ireg (cfg);
2937 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2941 g_assert (ins_is_compare(last_ins));
2942 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2943 last_ins->dreg = mono_alloc_ireg (cfg);
2944 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2948 g_assert (ins_is_compare(last_ins));
2949 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2950 last_ins->dreg = mono_alloc_ireg (cfg);
2951 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2955 g_assert (ins_is_compare(last_ins));
2956 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2957 last_ins->dreg = mono_alloc_ireg (cfg);
2958 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2962 g_assert (ins_is_compare(last_ins));
2963 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2964 last_ins->dreg = mono_alloc_ireg (cfg);
2965 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2969 g_assert (ins_is_compare(last_ins));
2970 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2971 last_ins->dreg = mono_alloc_ireg (cfg);
2972 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2977 g_assert (ins_is_compare(last_ins));
2978 last_ins->opcode = OP_IXOR;
2979 last_ins->dreg = mono_alloc_ireg(cfg);
2980 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2985 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2986 NULLIFY_INS(last_ins);
2992 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2993 NULLIFY_INS(last_ins);
2998 g_assert (ins_is_compare(last_ins));
2999 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
3000 MONO_DELETE_INS(bb, last_ins);
3005 g_assert (ins_is_compare(last_ins));
3006 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
3007 MONO_DELETE_INS(bb, last_ins);
3010 case OP_COND_EXC_EQ:
3011 case OP_COND_EXC_IEQ:
3012 g_assert (ins_is_compare(last_ins));
3013 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
3014 MONO_DELETE_INS(bb, last_ins);
3017 case OP_COND_EXC_GE:
3018 case OP_COND_EXC_IGE:
3019 g_assert (ins_is_compare(last_ins));
3020 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
3021 MONO_DELETE_INS(bb, last_ins);
3024 case OP_COND_EXC_GT:
3025 case OP_COND_EXC_IGT:
3026 g_assert (ins_is_compare(last_ins));
3027 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
3028 MONO_DELETE_INS(bb, last_ins);
3031 case OP_COND_EXC_LE:
3032 case OP_COND_EXC_ILE:
3033 g_assert (ins_is_compare(last_ins));
3034 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
3035 MONO_DELETE_INS(bb, last_ins);
3038 case OP_COND_EXC_LT:
3039 case OP_COND_EXC_ILT:
3040 g_assert (ins_is_compare(last_ins));
3041 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
3042 MONO_DELETE_INS(bb, last_ins);
3045 case OP_COND_EXC_NE_UN:
3046 case OP_COND_EXC_INE_UN:
3047 g_assert (ins_is_compare(last_ins));
3048 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
3049 MONO_DELETE_INS(bb, last_ins);
3052 case OP_COND_EXC_GE_UN:
3053 case OP_COND_EXC_IGE_UN:
3054 g_assert (ins_is_compare(last_ins));
3055 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
3056 MONO_DELETE_INS(bb, last_ins);
3059 case OP_COND_EXC_GT_UN:
3060 case OP_COND_EXC_IGT_UN:
3061 g_assert (ins_is_compare(last_ins));
3062 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
3063 MONO_DELETE_INS(bb, last_ins);
3066 case OP_COND_EXC_LE_UN:
3067 case OP_COND_EXC_ILE_UN:
3068 g_assert (ins_is_compare(last_ins));
3069 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
3070 MONO_DELETE_INS(bb, last_ins);
3073 case OP_COND_EXC_LT_UN:
3074 case OP_COND_EXC_ILT_UN:
3075 g_assert (ins_is_compare(last_ins));
3076 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
3077 MONO_DELETE_INS(bb, last_ins);
3080 case OP_COND_EXC_OV:
3081 case OP_COND_EXC_IOV: {
3082 int tmp1, tmp2, tmp3, tmp4, tmp5;
3083 MonoInst *pos = last_ins;
3085 /* Overflow happens if
3086 * neg + neg = pos or
3089 * (bit31s of operands match) AND (bit31 of operand
3090 * != bit31 of result)
3091 * XOR of the high bit returns 0 if the signs match
3092 * XOR of that with the high bit of the result return 1
3095 g_assert (last_ins->opcode == OP_IADC);
3097 tmp1 = mono_alloc_ireg (cfg);
3098 tmp2 = mono_alloc_ireg (cfg);
3099 tmp3 = mono_alloc_ireg (cfg);
3100 tmp4 = mono_alloc_ireg (cfg);
3101 tmp5 = mono_alloc_ireg (cfg);
3103 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3104 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
3106 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3107 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
3108 INS (pos, OP_INOT, tmp3, tmp2, -1);
3110 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3111 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
3112 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3114 /* Now, if (tmp5 == 0) then overflow */
3115 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3120 case OP_COND_EXC_NO:
3121 case OP_COND_EXC_INO:
3122 g_assert_not_reached ();
3126 case OP_COND_EXC_IC:
3127 g_assert_not_reached ();
3130 case OP_COND_EXC_NC:
3131 case OP_COND_EXC_INC:
3132 g_assert_not_reached ();
3138 bb->last_ins = last_ins;
3139 bb->max_vreg = cfg->next_vreg;
3142 if (cfg->verbose_level > 2) {
3145 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3146 MONO_BB_FOR_EACH_INS (bb, ins) {
3147 mono_print_ins_index (idx++, ins);
3156 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3158 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3160 mips_truncwd (code, mips_ftemp, sreg);
3162 mips_cvtwd (code, mips_ftemp, sreg);
3164 mips_mfc1 (code, dreg, mips_ftemp);
3167 mips_andi (code, dreg, dreg, 0xff);
3168 else if (size == 2) {
3169 mips_sll (code, dreg, dreg, 16);
3170 mips_srl (code, dreg, dreg, 16);
3174 mips_sll (code, dreg, dreg, 24);
3175 mips_sra (code, dreg, dreg, 24);
3177 else if (size == 2) {
3178 mips_sll (code, dreg, dreg, 16);
3179 mips_sra (code, dreg, dreg, 16);
3186 * emit_load_volatile_arguments:
3188 * Load volatile arguments from the stack to the original input registers.
3189 * Required before a tail call.
3192 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3194 MonoMethod *method = cfg->method;
3195 MonoMethodSignature *sig;
3200 sig = mono_method_signature (method);
3202 if (!cfg->arch.cinfo)
3203 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
3204 cinfo = cfg->arch.cinfo;
3206 if (cinfo->struct_ret) {
3207 ArgInfo *ainfo = &cinfo->ret;
3208 inst = cfg->vret_addr;
3209 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3212 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3213 ArgInfo *ainfo = cinfo->args + i;
3214 inst = cfg->args [i];
3215 if (inst->opcode == OP_REGVAR) {
3216 if (ainfo->storage == ArgInIReg)
3217 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3218 else if (ainfo->storage == ArgInFReg)
3219 g_assert_not_reached();
3220 else if (ainfo->storage == ArgOnStack) {
3223 g_assert_not_reached ();
3225 if (ainfo->storage == ArgInIReg) {
3226 g_assert (mips_is_imm16 (inst->inst_offset));
3227 switch (ainfo->size) {
3229 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3232 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3236 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3239 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3240 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3243 g_assert_not_reached ();
3246 } else if (ainfo->storage == ArgOnStack) {
3248 } else if (ainfo->storage == ArgInFReg) {
3249 g_assert (mips_is_imm16 (inst->inst_offset));
3250 if (ainfo->size == 8) {
3251 #if _MIPS_SIM == _ABIO32
3252 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3253 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3254 #elif _MIPS_SIM == _ABIN32
3255 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3258 else if (ainfo->size == 4)
3259 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3261 g_assert_not_reached ();
3262 } else if (ainfo->storage == ArgStructByVal) {
3264 int doffset = inst->inst_offset;
3266 g_assert (mips_is_imm16 (inst->inst_offset));
3267 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3268 for (i = 0; i < ainfo->size; ++i) {
3269 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3270 doffset += SIZEOF_REGISTER;
3272 } else if (ainfo->storage == ArgStructByAddr) {
3273 g_assert (mips_is_imm16 (inst->inst_offset));
3274 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3276 g_assert_not_reached ();
3284 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3286 int size = cfg->param_area;
3288 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3289 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3294 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3295 if (ppc_is_imm16 (-size)) {
3296 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3298 ppc_load (code, ppc_r11, -size);
3299 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3306 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3308 int size = cfg->param_area;
3310 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3311 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3316 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3317 if (ppc_is_imm16 (size)) {
3318 ppc_stwu (code, ppc_r0, size, ppc_sp);
3320 ppc_load (code, ppc_r11, size);
3321 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3328 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3333 guint8 *code = cfg->native_code + cfg->code_len;
3334 MonoInst *last_ins = NULL;
3335 guint last_offset = 0;
3339 /* we don't align basic blocks of loops on mips */
3341 if (cfg->verbose_level > 2)
3342 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3344 cpos = bb->max_offset;
3347 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3348 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3349 g_assert (!mono_compile_aot);
3352 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3353 /* this is not thread save, but good enough */
3354 /* fixme: howto handle overflows? */
3355 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3356 mips_lw (code, mips_temp, mips_at, 0);
3357 mips_addiu (code, mips_temp, mips_temp, 1);
3358 mips_sw (code, mips_temp, mips_at, 0);
3361 MONO_BB_FOR_EACH_INS (bb, ins) {
3362 offset = code - cfg->native_code;
3364 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3366 if (offset > (cfg->code_size - max_len - 16)) {
3367 cfg->code_size *= 2;
3368 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3369 code = cfg->native_code + offset;
3371 mono_debug_record_line_number (cfg, ins, offset);
3372 if (cfg->verbose_level > 2) {
3373 g_print (" @ 0x%x\t", offset);
3374 mono_print_ins_index (ins_cnt++, ins);
3376 /* Check for virtual regs that snuck by */
3377 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3379 switch (ins->opcode) {
3380 case OP_RELAXED_NOP:
3383 case OP_DUMMY_STORE:
3384 case OP_NOT_REACHED:
3387 case OP_SEQ_POINT: {
3388 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3389 guint32 addr = (guint32)ss_trigger_page;
3391 mips_load_const (code, mips_t9, addr);
3392 mips_lw (code, mips_t9, mips_t9, 0);
3395 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3398 * A placeholder for a possible breakpoint inserted by
3399 * mono_arch_set_breakpoint ().
3401 /* mips_load_const () + mips_lw */
3408 g_assert_not_reached();
3410 emit_tls_access (code, ins->dreg, ins->inst_offset);
3414 mips_mult (code, ins->sreg1, ins->sreg2);
3415 mips_mflo (code, ins->dreg);
3416 mips_mfhi (code, ins->dreg+1);
3419 mips_multu (code, ins->sreg1, ins->sreg2);
3420 mips_mflo (code, ins->dreg);
3421 mips_mfhi (code, ins->dreg+1);
3423 case OP_MEMORY_BARRIER:
3428 case OP_STOREI1_MEMBASE_IMM:
3429 mips_load_const (code, mips_temp, ins->inst_imm);
3430 if (mips_is_imm16 (ins->inst_offset)) {
3431 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3433 mips_load_const (code, mips_at, ins->inst_offset);
3434 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3437 case OP_STOREI2_MEMBASE_IMM:
3438 mips_load_const (code, mips_temp, ins->inst_imm);
3439 if (mips_is_imm16 (ins->inst_offset)) {
3440 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3442 mips_load_const (code, mips_at, ins->inst_offset);
3443 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3446 case OP_STOREI8_MEMBASE_IMM:
3447 mips_load_const (code, mips_temp, ins->inst_imm);
3448 if (mips_is_imm16 (ins->inst_offset)) {
3449 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3451 mips_load_const (code, mips_at, ins->inst_offset);
3452 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3455 case OP_STORE_MEMBASE_IMM:
3456 case OP_STOREI4_MEMBASE_IMM:
3457 mips_load_const (code, mips_temp, ins->inst_imm);
3458 if (mips_is_imm16 (ins->inst_offset)) {
3459 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3461 mips_load_const (code, mips_at, ins->inst_offset);
3462 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3465 case OP_STOREI1_MEMBASE_REG:
3466 if (mips_is_imm16 (ins->inst_offset)) {
3467 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3469 mips_load_const (code, mips_at, ins->inst_offset);
3470 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3471 mips_sb (code, ins->sreg1, mips_at, 0);
3474 case OP_STOREI2_MEMBASE_REG:
3475 if (mips_is_imm16 (ins->inst_offset)) {
3476 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3478 mips_load_const (code, mips_at, ins->inst_offset);
3479 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3480 mips_sh (code, ins->sreg1, mips_at, 0);
3483 case OP_STORE_MEMBASE_REG:
3484 case OP_STOREI4_MEMBASE_REG:
3485 if (mips_is_imm16 (ins->inst_offset)) {
3486 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3488 mips_load_const (code, mips_at, ins->inst_offset);
3489 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3490 mips_sw (code, ins->sreg1, mips_at, 0);
3493 case OP_STOREI8_MEMBASE_REG:
3494 if (mips_is_imm16 (ins->inst_offset)) {
3495 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3497 mips_load_const (code, mips_at, ins->inst_offset);
3498 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3499 mips_sd (code, ins->sreg1, mips_at, 0);
3503 g_assert_not_reached ();
3504 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3505 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3507 case OP_LOADI8_MEMBASE:
3508 if (mips_is_imm16 (ins->inst_offset)) {
3509 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3511 mips_load_const (code, mips_at, ins->inst_offset);
3512 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3513 mips_ld (code, ins->dreg, mips_at, 0);
3516 case OP_LOAD_MEMBASE:
3517 case OP_LOADI4_MEMBASE:
3518 case OP_LOADU4_MEMBASE:
3519 g_assert (ins->dreg != -1);
3520 if (mips_is_imm16 (ins->inst_offset)) {
3521 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3523 mips_load_const (code, mips_at, ins->inst_offset);
3524 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3525 mips_lw (code, ins->dreg, mips_at, 0);
3528 case OP_LOADI1_MEMBASE:
3529 if (mips_is_imm16 (ins->inst_offset)) {
3530 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3532 mips_load_const (code, mips_at, ins->inst_offset);
3533 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3534 mips_lb (code, ins->dreg, mips_at, 0);
3537 case OP_LOADU1_MEMBASE:
3538 if (mips_is_imm16 (ins->inst_offset)) {
3539 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3541 mips_load_const (code, mips_at, ins->inst_offset);
3542 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3543 mips_lbu (code, ins->dreg, mips_at, 0);
3546 case OP_LOADI2_MEMBASE:
3547 if (mips_is_imm16 (ins->inst_offset)) {
3548 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3550 mips_load_const (code, mips_at, ins->inst_offset);
3551 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3552 mips_lh (code, ins->dreg, mips_at, 0);
3555 case OP_LOADU2_MEMBASE:
3556 if (mips_is_imm16 (ins->inst_offset)) {
3557 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3559 mips_load_const (code, mips_at, ins->inst_offset);
3560 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3561 mips_lhu (code, ins->dreg, mips_at, 0);
3564 case OP_ICONV_TO_I1:
3565 mips_sll (code, mips_at, ins->sreg1, 24);
3566 mips_sra (code, ins->dreg, mips_at, 24);
3568 case OP_ICONV_TO_I2:
3569 mips_sll (code, mips_at, ins->sreg1, 16);
3570 mips_sra (code, ins->dreg, mips_at, 16);
3572 case OP_ICONV_TO_U1:
3573 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3575 case OP_ICONV_TO_U2:
3576 mips_sll (code, mips_at, ins->sreg1, 16);
3577 mips_srl (code, ins->dreg, mips_at, 16);
3580 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3583 g_assert (mips_is_imm16 (ins->inst_imm));
3584 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3587 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3590 g_assert (mips_is_imm16 (ins->inst_imm));
3591 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3595 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3596 * So instead of emitting a trap, we emit a call a C function and place a
3599 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3600 (gpointer)"mono_break");
3601 mips_load (code, mips_t9, 0x1f1f1f1f);
3602 mips_jalr (code, mips_t9, mips_ra);
3606 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3609 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3614 g_assert (mips_is_imm16 (ins->inst_imm));
3615 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3618 g_assert (mips_is_imm16 (ins->inst_imm));
3619 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3623 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3626 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3631 // we add the negated value
3632 g_assert (mips_is_imm16 (-ins->inst_imm));
3633 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3637 // we add the negated value
3638 g_assert (mips_is_imm16 (-ins->inst_imm));
3639 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3644 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3650 g_assert (!(ins->inst_imm & 0xffff0000));
3651 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3656 guint32 *divisor_is_m1;
3657 guint32 *dividend_is_minvalue;
3658 guint32 *divisor_is_zero;
3660 mips_load_const (code, mips_at, -1);
3661 divisor_is_m1 = (guint32 *)(void *)code;
3662 mips_bne (code, ins->sreg2, mips_at, 0);
3663 mips_lui (code, mips_at, mips_zero, 0x8000);
3664 dividend_is_minvalue = (guint32 *)(void *)code;
3665 mips_bne (code, ins->sreg1, mips_at, 0);
3668 /* Divide Int32.MinValue by -1 -- throw exception */
3669 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3671 mips_patch (divisor_is_m1, (guint32)code);
3672 mips_patch (dividend_is_minvalue, (guint32)code);
3674 /* Put divide in branch delay slot (NOT YET) */
3675 divisor_is_zero = (guint32 *)(void *)code;
3676 mips_bne (code, ins->sreg2, mips_zero, 0);
3679 /* Divide by zero -- throw exception */
3680 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3682 mips_patch (divisor_is_zero, (guint32)code);
3683 mips_div (code, ins->sreg1, ins->sreg2);
3684 if (ins->opcode == OP_IDIV)
3685 mips_mflo (code, ins->dreg);
3687 mips_mfhi (code, ins->dreg);
3692 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3694 /* Put divide in branch delay slot (NOT YET) */
3695 mips_bne (code, ins->sreg2, mips_zero, 0);
3698 /* Divide by zero -- throw exception */
3699 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3701 mips_patch (divisor_is_zero, (guint32)code);
3702 mips_divu (code, ins->sreg1, ins->sreg2);
3703 if (ins->opcode == OP_IDIV_UN)
3704 mips_mflo (code, ins->dreg);
3706 mips_mfhi (code, ins->dreg);
3710 g_assert_not_reached ();
3712 ppc_load (code, ppc_r11, ins->inst_imm);
3713 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3714 ppc_mfspr (code, ppc_r0, ppc_xer);
3715 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3716 /* FIXME: use OverflowException for 0x80000000/-1 */
3717 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3719 g_assert_not_reached();
3722 g_assert_not_reached ();
3724 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3728 g_assert (!(ins->inst_imm & 0xffff0000));
3729 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3732 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3736 /* unsigned 16-bit immediate */
3737 g_assert (!(ins->inst_imm & 0xffff0000));
3738 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3741 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3745 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3748 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3751 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3755 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3758 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3761 case OP_ISHR_UN_IMM:
3762 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3764 case OP_LSHR_UN_IMM:
3765 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3768 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3771 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3775 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3778 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3781 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3785 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3787 mips_mult (code, ins->sreg1, ins->sreg2);
3788 mips_mflo (code, ins->dreg);
3793 #if SIZEOF_REGISTER == 8
3795 mips_dmult (code, ins->sreg1, ins->sreg2);
3796 mips_mflo (code, ins->dreg);
3801 mips_mult (code, ins->sreg1, ins->sreg2);
3802 mips_mflo (code, ins->dreg);
3803 mips_mfhi (code, mips_at);
3806 mips_sra (code, mips_temp, ins->dreg, 31);
3807 patch = (guint32 *)(void *)code;
3808 mips_beq (code, mips_temp, mips_at, 0);
3810 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3811 mips_patch (patch, (guint32)code);
3814 case OP_IMUL_OVF_UN: {
3816 mips_mult (code, ins->sreg1, ins->sreg2);
3817 mips_mflo (code, ins->dreg);
3818 mips_mfhi (code, mips_at);
3821 patch = (guint32 *)(void *)code;
3822 mips_beq (code, mips_at, mips_zero, 0);
3824 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3825 mips_patch (patch, (guint32)code);
3829 mips_load_const (code, ins->dreg, ins->inst_c0);
3831 #if SIZEOF_REGISTER == 8
3833 mips_load_const (code, ins->dreg, ins->inst_c0);
3837 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3838 mips_load (code, ins->dreg, 0);
3842 mips_mtc1 (code, ins->dreg, ins->sreg1);
3844 case OP_MIPS_MTC1S_2:
3845 mips_mtc1 (code, ins->dreg, ins->sreg1);
3846 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3849 mips_mfc1 (code, ins->dreg, ins->sreg1);
3852 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3856 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3858 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3859 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3863 case OP_ICONV_TO_I4:
3864 case OP_ICONV_TO_U4:
3866 if (ins->dreg != ins->sreg1)
3867 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3869 #if SIZEOF_REGISTER == 8
3871 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3872 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3875 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3876 mips_dsra (code, ins->dreg, ins->dreg, 32);
3880 int lsreg = mips_v0 + ls_word_idx;
3881 int msreg = mips_v0 + ms_word_idx;
3883 /* Get sreg1 into lsreg, sreg2 into msreg */
3885 if (ins->sreg1 == msreg) {
3886 if (ins->sreg1 != mips_at)
3887 MIPS_MOVE (code, mips_at, ins->sreg1);
3888 if (ins->sreg2 != msreg)
3889 MIPS_MOVE (code, msreg, ins->sreg2);
3890 MIPS_MOVE (code, lsreg, mips_at);
3893 if (ins->sreg2 != msreg)
3894 MIPS_MOVE (code, msreg, ins->sreg2);
3895 if (ins->sreg1 != lsreg)
3896 MIPS_MOVE (code, lsreg, ins->sreg1);
3901 if (ins->dreg != ins->sreg1) {
3902 mips_fmovd (code, ins->dreg, ins->sreg1);
3906 /* Convert from double to float and leave it there */
3907 mips_cvtsd (code, ins->dreg, ins->sreg1);
3909 case OP_FCONV_TO_R4:
3911 mips_cvtsd (code, ins->dreg, ins->sreg1);
3913 /* Just a move, no precision change */
3914 if (ins->dreg != ins->sreg1) {
3915 mips_fmovd (code, ins->dreg, ins->sreg1);
3920 code = emit_load_volatile_arguments(cfg, code);
3923 * Pop our stack, then jump to specified method (tail-call)
3924 * Keep in sync with mono_arch_emit_epilog
3926 code = mono_arch_emit_epilog_sub (cfg, code);
3928 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3929 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3930 mips_load (code, mips_t9, 0);
3931 mips_jr (code, mips_t9);
3935 /* ensure ins->sreg1 is not NULL */
3936 mips_lw (code, mips_zero, ins->sreg1, 0);
3939 g_assert (mips_is_imm16 (cfg->sig_cookie));
3940 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3941 mips_sw (code, mips_at, ins->sreg1, 0);
3954 case OP_VOIDCALL_REG:
3956 case OP_FCALL_MEMBASE:
3957 case OP_LCALL_MEMBASE:
3958 case OP_VCALL_MEMBASE:
3959 case OP_VCALL2_MEMBASE:
3960 case OP_VOIDCALL_MEMBASE:
3961 case OP_CALL_MEMBASE:
3962 call = (MonoCallInst*)ins;
3963 switch (ins->opcode) {
3970 if (ins->flags & MONO_INST_HAS_METHOD) {
3971 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3972 mips_load (code, mips_t9, call->method);
3975 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3976 mips_load (code, mips_t9, call->fptr);
3978 mips_jalr (code, mips_t9, mips_ra);
3985 case OP_VOIDCALL_REG:
3987 MIPS_MOVE (code, mips_t9, ins->sreg1);
3988 mips_jalr (code, mips_t9, mips_ra);
3991 case OP_FCALL_MEMBASE:
3992 case OP_LCALL_MEMBASE:
3993 case OP_VCALL_MEMBASE:
3994 case OP_VCALL2_MEMBASE:
3995 case OP_VOIDCALL_MEMBASE:
3996 case OP_CALL_MEMBASE:
3997 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3998 mips_jalr (code, mips_t9, mips_ra);
4002 #if PROMOTE_R4_TO_R8
4003 /* returned an FP R4 (single), promote to R8 (double) in place */
4004 switch (ins->opcode) {
4007 case OP_FCALL_MEMBASE:
4008 if (call->signature->ret->type == MONO_TYPE_R4)
4009 mips_cvtds (code, mips_f0, mips_f0);
4017 int area_offset = cfg->param_area;
4019 /* Round up ins->sreg1, mips_at ends up holding size */
4020 mips_addiu (code, mips_at, ins->sreg1, 31);
4021 mips_addiu (code, mips_temp, mips_zero, ~31);
4022 mips_and (code, mips_at, mips_at, mips_temp);
4024 mips_subu (code, mips_sp, mips_sp, mips_at);
4025 g_assert (mips_is_imm16 (area_offset));
4026 mips_addiu (code, ins->dreg, mips_sp, area_offset);
4028 if (ins->flags & MONO_INST_INIT) {
4031 buf = (guint32*)(void*)code;
4032 mips_beq (code, mips_at, mips_zero, 0);
4035 mips_move (code, mips_temp, ins->dreg);
4036 mips_sb (code, mips_zero, mips_temp, 0);
4037 mips_addiu (code, mips_at, mips_at, -1);
4038 mips_bne (code, mips_at, mips_zero, -3);
4039 mips_addiu (code, mips_temp, mips_temp, 1);
4041 mips_patch (buf, (guint32)code);
4046 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
4047 mips_move (code, mips_a0, ins->sreg1);
4048 mips_call (code, mips_t9, addr);
4049 mips_break (code, 0xfc);
4053 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
4054 mips_move (code, mips_a0, ins->sreg1);
4055 mips_call (code, mips_t9, addr);
4056 mips_break (code, 0xfb);
4059 case OP_START_HANDLER: {
4061 * The START_HANDLER instruction marks the beginning of
4062 * a handler block. It is called using a call
4063 * instruction, so mips_ra contains the return address.
4064 * Since the handler executes in the same stack frame
4065 * as the method itself, we can't use save/restore to
4066 * save the return address. Instead, we save it into
4067 * a dedicated variable.
4069 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4070 g_assert (spvar->inst_basereg != mips_sp);
4071 code = emit_reserve_param_area (cfg, code);
4073 if (mips_is_imm16 (spvar->inst_offset)) {
4074 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4076 mips_load_const (code, mips_at, spvar->inst_offset);
4077 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4078 mips_sw (code, mips_ra, mips_at, 0);
4082 case OP_ENDFILTER: {
4083 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4084 g_assert (spvar->inst_basereg != mips_sp);
4085 code = emit_unreserve_param_area (cfg, code);
4087 if (ins->sreg1 != mips_v0)
4088 MIPS_MOVE (code, mips_v0, ins->sreg1);
4089 if (mips_is_imm16 (spvar->inst_offset)) {
4090 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4092 mips_load_const (code, mips_at, spvar->inst_offset);
4093 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4094 mips_lw (code, mips_ra, mips_at, 0);
4096 mips_jr (code, mips_ra);
4100 case OP_ENDFINALLY: {
4101 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4102 g_assert (spvar->inst_basereg != mips_sp);
4103 code = emit_unreserve_param_area (cfg, code);
4104 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
4105 mips_jalr (code, mips_t9, mips_ra);
4109 case OP_CALL_HANDLER:
4110 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4111 mips_lui (code, mips_t9, mips_zero, 0);
4112 mips_addiu (code, mips_t9, mips_t9, 0);
4113 mips_jalr (code, mips_t9, mips_ra);
4115 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4116 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4119 ins->inst_c0 = code - cfg->native_code;
4122 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4123 if (cfg->arch.long_branch) {
4124 mips_lui (code, mips_at, mips_zero, 0);
4125 mips_addiu (code, mips_at, mips_at, 0);
4126 mips_jr (code, mips_at);
4130 mips_beq (code, mips_zero, mips_zero, 0);
4135 mips_jr (code, ins->sreg1);
4141 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4142 if (offset > (cfg->code_size - max_len - 16)) {
4143 cfg->code_size += max_len;
4144 cfg->code_size *= 2;
4145 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4146 code = cfg->native_code + offset;
4148 g_assert (ins->sreg1 != -1);
4149 mips_sll (code, mips_at, ins->sreg1, 2);
4150 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4151 MIPS_MOVE (code, mips_t8, mips_ra);
4152 mips_bgezal (code, mips_zero, 1); /* bal */
4154 mips_addu (code, mips_t9, mips_ra, mips_at);
4155 /* Table is 16 or 20 bytes from target of bal above */
4156 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4157 MIPS_MOVE (code, mips_ra, mips_t8);
4158 mips_lw (code, mips_t9, mips_t9, 20);
4161 mips_lw (code, mips_t9, mips_t9, 16);
4162 mips_jalr (code, mips_t9, mips_t8);
4164 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4165 mips_emit32 (code, 0xfefefefe);
4170 mips_addiu (code, ins->dreg, mips_zero, 1);
4171 mips_beq (code, mips_at, mips_zero, 2);
4173 MIPS_MOVE (code, ins->dreg, mips_zero);
4179 mips_addiu (code, ins->dreg, mips_zero, 1);
4180 mips_bltz (code, mips_at, 2);
4182 MIPS_MOVE (code, ins->dreg, mips_zero);
4188 mips_addiu (code, ins->dreg, mips_zero, 1);
4189 mips_bgtz (code, mips_at, 2);
4191 MIPS_MOVE (code, ins->dreg, mips_zero);
4194 case OP_MIPS_COND_EXC_EQ:
4195 case OP_MIPS_COND_EXC_GE:
4196 case OP_MIPS_COND_EXC_GT:
4197 case OP_MIPS_COND_EXC_LE:
4198 case OP_MIPS_COND_EXC_LT:
4199 case OP_MIPS_COND_EXC_NE_UN:
4200 case OP_MIPS_COND_EXC_GE_UN:
4201 case OP_MIPS_COND_EXC_GT_UN:
4202 case OP_MIPS_COND_EXC_LE_UN:
4203 case OP_MIPS_COND_EXC_LT_UN:
4205 case OP_MIPS_COND_EXC_OV:
4206 case OP_MIPS_COND_EXC_NO:
4207 case OP_MIPS_COND_EXC_C:
4208 case OP_MIPS_COND_EXC_NC:
4210 case OP_MIPS_COND_EXC_IEQ:
4211 case OP_MIPS_COND_EXC_IGE:
4212 case OP_MIPS_COND_EXC_IGT:
4213 case OP_MIPS_COND_EXC_ILE:
4214 case OP_MIPS_COND_EXC_ILT:
4215 case OP_MIPS_COND_EXC_INE_UN:
4216 case OP_MIPS_COND_EXC_IGE_UN:
4217 case OP_MIPS_COND_EXC_IGT_UN:
4218 case OP_MIPS_COND_EXC_ILE_UN:
4219 case OP_MIPS_COND_EXC_ILT_UN:
4221 case OP_MIPS_COND_EXC_IOV:
4222 case OP_MIPS_COND_EXC_INO:
4223 case OP_MIPS_COND_EXC_IC:
4224 case OP_MIPS_COND_EXC_INC: {
4228 /* If the condition is true, raise the exception */
4230 /* need to reverse test to skip around exception raising */
4232 /* For the moment, branch around a branch to avoid reversing
4235 /* Remember, an unpatched branch to 0 branches to the delay slot */
4236 switch (ins->opcode) {
4237 case OP_MIPS_COND_EXC_EQ:
4238 throw = (guint32 *)(void *)code;
4239 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4243 case OP_MIPS_COND_EXC_NE_UN:
4244 throw = (guint32 *)(void *)code;
4245 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4249 case OP_MIPS_COND_EXC_LE_UN:
4250 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4251 throw = (guint32 *)(void *)code;
4252 mips_beq (code, mips_at, mips_zero, 0);
4256 case OP_MIPS_COND_EXC_GT:
4257 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4258 throw = (guint32 *)(void *)code;
4259 mips_bne (code, mips_at, mips_zero, 0);
4263 case OP_MIPS_COND_EXC_GT_UN:
4264 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4265 throw = (guint32 *)(void *)code;
4266 mips_bne (code, mips_at, mips_zero, 0);
4270 case OP_MIPS_COND_EXC_LT:
4271 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4272 throw = (guint32 *)(void *)code;
4273 mips_bne (code, mips_at, mips_zero, 0);
4277 case OP_MIPS_COND_EXC_LT_UN:
4278 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4279 throw = (guint32 *)(void *)code;
4280 mips_bne (code, mips_at, mips_zero, 0);
4285 /* Not yet implemented */
4286 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4287 g_assert_not_reached ();
4289 skip = (guint32 *)(void *)code;
4290 mips_beq (code, mips_zero, mips_zero, 0);
4292 mips_patch (throw, (guint32)code);
4293 code = mips_emit_exc_by_name (code, ins->inst_p1);
4294 mips_patch (skip, (guint32)code);
4295 cfg->bb_exit->max_offset += 24;
4304 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4307 /* floating point opcodes */
4310 if (((guint32)ins->inst_p0) & (1 << 15))
4311 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4313 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4314 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4316 mips_load_const (code, mips_at, ins->inst_p0);
4317 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4318 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4322 if (((guint32)ins->inst_p0) & (1 << 15))
4323 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4325 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4326 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4327 #if PROMOTE_R4_TO_R8
4328 mips_cvtds (code, ins->dreg, ins->dreg);
4331 case OP_STORER8_MEMBASE_REG:
4332 if (mips_is_imm16 (ins->inst_offset)) {
4333 #if _MIPS_SIM == _ABIO32
4334 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4335 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4336 #elif _MIPS_SIM == _ABIN32
4337 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4340 mips_load_const (code, mips_at, ins->inst_offset);
4341 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4342 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4343 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4346 case OP_LOADR8_MEMBASE:
4347 if (mips_is_imm16 (ins->inst_offset)) {
4348 #if _MIPS_SIM == _ABIO32
4349 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4350 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4351 #elif _MIPS_SIM == _ABIN32
4352 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4355 mips_load_const (code, mips_at, ins->inst_offset);
4356 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4357 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4358 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4361 case OP_STORER4_MEMBASE_REG:
4362 g_assert (mips_is_imm16 (ins->inst_offset));
4363 #if PROMOTE_R4_TO_R8
4364 /* Need to convert ins->sreg1 to single-precision first */
4365 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4366 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4368 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4372 g_assert (mips_is_imm16 (ins->inst_offset));
4373 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4375 case OP_LOADR4_MEMBASE:
4376 g_assert (mips_is_imm16 (ins->inst_offset));
4377 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4378 #if PROMOTE_R4_TO_R8
4379 /* Convert to double precision in place */
4380 mips_cvtds (code, ins->dreg, ins->dreg);
4383 case OP_LOADR4_MEMINDEX:
4384 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4385 mips_lwc1 (code, ins->dreg, mips_at, 0);
4387 case OP_LOADR8_MEMINDEX:
4388 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4389 #if _MIPS_SIM == _ABIO32
4390 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4391 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4392 #elif _MIPS_SIM == _ABIN32
4393 mips_ldc1 (code, ins->dreg, mips_at, 0);
4396 case OP_STORER4_MEMINDEX:
4397 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4398 #if PROMOTE_R4_TO_R8
4399 /* Need to convert ins->sreg1 to single-precision first */
4400 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4401 mips_swc1 (code, mips_ftemp, mips_at, 0);
4403 mips_swc1 (code, ins->sreg1, mips_at, 0);
4406 case OP_STORER8_MEMINDEX:
4407 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4408 #if _MIPS_SIM == _ABIO32
4409 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4410 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4411 #elif _MIPS_SIM == _ABIN32
4412 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4415 case OP_ICONV_TO_R_UN: {
4416 static const guint64 adjust_val = 0x41F0000000000000ULL;
4418 /* convert unsigned int to double */
4419 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4420 mips_bgez (code, ins->sreg1, 5);
4421 mips_cvtdw (code, ins->dreg, mips_ftemp);
4423 mips_load (code, mips_at, (guint32) &adjust_val);
4424 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4425 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4426 /* target is here */
4429 case OP_ICONV_TO_R4:
4430 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4431 mips_cvtsw (code, ins->dreg, mips_ftemp);
4432 mips_cvtds (code, ins->dreg, ins->dreg);
4434 case OP_ICONV_TO_R8:
4435 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4436 mips_cvtdw (code, ins->dreg, mips_ftemp);
4438 case OP_FCONV_TO_I1:
4439 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4441 case OP_FCONV_TO_U1:
4442 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4444 case OP_FCONV_TO_I2:
4445 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4447 case OP_FCONV_TO_U2:
4448 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4450 case OP_FCONV_TO_I4:
4452 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4454 case OP_FCONV_TO_U4:
4456 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4459 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4462 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4465 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4468 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4471 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4474 mips_fnegd (code, ins->dreg, ins->sreg1);
4477 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4478 mips_addiu (code, ins->dreg, mips_zero, 1);
4479 mips_fbtrue (code, 2);
4481 MIPS_MOVE (code, ins->dreg, mips_zero);
4484 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4485 mips_addiu (code, ins->dreg, mips_zero, 1);
4486 mips_fbtrue (code, 2);
4488 MIPS_MOVE (code, ins->dreg, mips_zero);
4491 /* Less than, or Unordered */
4492 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4493 mips_addiu (code, ins->dreg, mips_zero, 1);
4494 mips_fbtrue (code, 2);
4496 MIPS_MOVE (code, ins->dreg, mips_zero);
4499 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4500 MIPS_MOVE (code, ins->dreg, mips_zero);
4501 mips_fbtrue (code, 2);
4503 mips_addiu (code, ins->dreg, mips_zero, 1);
4506 /* Greater than, or Unordered */
4507 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4508 MIPS_MOVE (code, ins->dreg, mips_zero);
4509 mips_fbtrue (code, 2);
4511 mips_addiu (code, ins->dreg, mips_zero, 1);
4516 case OP_MIPS_FBLT_UN:
4518 case OP_MIPS_FBGT_UN:
4520 case OP_MIPS_FBGE_UN:
4522 case OP_MIPS_FBLE_UN: {
4524 gboolean is_true = TRUE, is_ordered = FALSE;
4525 guint32 *buf = NULL;
4527 switch (ins->opcode) {
4541 case OP_MIPS_FBLT_UN:
4542 cond = MIPS_FPU_ULT;
4550 case OP_MIPS_FBGT_UN:
4551 cond = MIPS_FPU_OLE;
4559 case OP_MIPS_FBGE_UN:
4560 cond = MIPS_FPU_OLT;
4564 cond = MIPS_FPU_OLE;
4568 case OP_MIPS_FBLE_UN:
4569 cond = MIPS_FPU_ULE;
4573 g_assert_not_reached ();
4577 /* Skip the check if unordered */
4578 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4580 buf = (guint32*)code;
4581 mips_fbtrue (code, 0);
4585 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4587 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4589 mips_fbtrue (code, 0);
4591 mips_fbfalse (code, 0);
4595 mips_patch (buf, (guint32)code);
4599 guint32 *branch_patch;
4601 mips_mfc1 (code, mips_at, ins->sreg1+1);
4602 mips_srl (code, mips_at, mips_at, 16+4);
4603 mips_andi (code, mips_at, mips_at, 2047);
4604 mips_addiu (code, mips_at, mips_at, -2047);
4606 branch_patch = (guint32 *)(void *)code;
4607 mips_bne (code, mips_at, mips_zero, 0);
4610 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4611 mips_patch (branch_patch, (guint32)code);
4612 mips_fmovd (code, ins->dreg, ins->sreg1);
4616 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4617 mips_load (code, ins->dreg, 0x0f0f0f0f);
4622 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4623 g_assert_not_reached ();
4626 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4627 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4628 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4629 g_assert_not_reached ();
4635 last_offset = offset;
4638 cfg->code_len = code - cfg->native_code;
4642 mono_arch_register_lowlevel_calls (void)
4647 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4649 MonoJumpInfo *patch_info;
4651 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4652 unsigned char *ip = patch_info->ip.i + code;
4653 const unsigned char *target = NULL;
4655 switch (patch_info->type) {
4656 case MONO_PATCH_INFO_IP:
4657 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4659 case MONO_PATCH_INFO_SWITCH: {
4660 gpointer *table = (gpointer *)patch_info->data.table->table;
4663 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4665 for (i = 0; i < patch_info->data.table->table_size; i++) {
4666 table [i] = (int)patch_info->data.table->table [i] + code;
4670 case MONO_PATCH_INFO_METHODCONST:
4671 case MONO_PATCH_INFO_CLASS:
4672 case MONO_PATCH_INFO_IMAGE:
4673 case MONO_PATCH_INFO_FIELD:
4674 case MONO_PATCH_INFO_VTABLE:
4675 case MONO_PATCH_INFO_IID:
4676 case MONO_PATCH_INFO_SFLDA:
4677 case MONO_PATCH_INFO_LDSTR:
4678 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4679 case MONO_PATCH_INFO_LDTOKEN:
4680 case MONO_PATCH_INFO_R4:
4681 case MONO_PATCH_INFO_R8:
4682 /* from OP_AOTCONST : lui + addiu */
4683 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4684 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4687 case MONO_PATCH_INFO_EXC_NAME:
4688 g_assert_not_reached ();
4689 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4692 case MONO_PATCH_INFO_NONE:
4693 /* everything is dealt with at epilog output time */
4696 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4697 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4704 * Allow tracing to work with this interface (with an optional argument)
4706 * This code is expected to be inserted just after the 'real' prolog code,
4707 * and before the first basic block. We need to allocate a 2nd, temporary
4708 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4712 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4715 int offset = cfg->arch.tracing_offset;
4721 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4722 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4723 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4724 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4725 #if _MIPS_SIM == _ABIN32
4727 /* FIXME: Need a separate region for these */
4728 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4729 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4730 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4731 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4735 mips_load_const (code, mips_a0, cfg->method);
4736 mips_addiu (code, mips_a1, mips_sp, offset);
4737 mips_call (code, mips_t9, func);
4740 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4741 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4742 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4743 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4744 #if _MIPS_SIM == _ABIN32
4747 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4748 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4749 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4750 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4761 mips_adjust_stackframe(MonoCompile *cfg)
4764 int delta, threshold, i;
4765 MonoMethodSignature *sig;
4768 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4771 /* adjust cfg->stack_offset for account for down-spilling */
4772 cfg->stack_offset += SIZEOF_REGISTER;
4774 /* re-align cfg->stack_offset if needed (due to var spilling) */
4775 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4776 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4777 if (cfg->verbose_level > 2) {
4778 g_print ("mips_adjust_stackframe:\n");
4779 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4781 threshold = cfg->arch.local_alloc_offset;
4782 ra_offset = cfg->stack_offset - sizeof(gpointer);
4783 if (cfg->verbose_level > 2) {
4784 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4787 sig = mono_method_signature (cfg->method);
4788 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4789 cfg->vret_addr->inst_offset += delta;
4791 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4792 MonoInst *inst = cfg->args [i];
4794 inst->inst_offset += delta;
4798 * loads and stores based off the frame reg that (used to) lie
4799 * above the spill var area need to be increased by 'delta'
4800 * to make room for the spill vars.
4802 /* Need to find loads and stores to adjust that
4803 * are above where the spillvars were inserted, but
4804 * which are not the spillvar references themselves.
4806 * Idea - since all offsets from fp are positive, make
4807 * spillvar offsets negative to begin with so we can spot
4812 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4816 if (cfg->verbose_level > 2) {
4817 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4819 MONO_BB_FOR_EACH_INS (bb, ins) {
4823 if (cfg->verbose_level > 2) {
4824 mono_print_ins_index (ins_cnt, ins);
4826 /* The == mips_sp tests catch FP spills */
4827 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4828 (ins->inst_basereg == mips_sp))) {
4829 switch (ins->opcode) {
4830 case OP_LOADI8_MEMBASE:
4831 case OP_LOADR8_MEMBASE:
4838 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4839 (ins->dreg == mips_sp))) {
4840 switch (ins->opcode) {
4841 case OP_STOREI8_MEMBASE_REG:
4842 case OP_STORER8_MEMBASE_REG:
4843 case OP_STOREI8_MEMBASE_IMM:
4851 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4854 if (ins->inst_c0 >= threshold) {
4855 ins->inst_c0 += delta;
4856 if (cfg->verbose_level > 2) {
4858 mono_print_ins_index (ins_cnt, ins);
4861 else if (ins->inst_c0 < 0) {
4862 /* Adj_c0 holds the size of the datatype. */
4863 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4864 if (cfg->verbose_level > 2) {
4866 mono_print_ins_index (ins_cnt, ins);
4869 g_assert (ins->inst_c0 != ra_offset);
4872 if (ins->inst_imm >= threshold) {
4873 ins->inst_imm += delta;
4874 if (cfg->verbose_level > 2) {
4876 mono_print_ins_index (ins_cnt, ins);
4879 g_assert (ins->inst_c0 != ra_offset);
4889 * Stack frame layout:
4891 * ------------------- sp + cfg->stack_usage + cfg->param_area
4892 * param area incoming
4893 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4895 * ------------------- sp + cfg->stack_usage
4897 * ------------------- sp + cfg->stack_usage-4
4899 * ------------------- sp +
4900 * MonoLMF structure optional
4901 * ------------------- sp + cfg->arch.lmf_offset
4902 * saved registers s0-s8
4903 * ------------------- sp + cfg->arch.iregs_offset
4905 * ------------------- sp + cfg->param_area
4906 * param area outgoing
4907 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4909 * ------------------- sp
4913 mono_arch_emit_prolog (MonoCompile *cfg)
4915 MonoMethod *method = cfg->method;
4916 MonoMethodSignature *sig;
4918 int alloc_size, pos, i, max_offset;
4919 int alloc2_size = 0;
4923 guint32 iregs_to_save = 0;
4925 guint32 fregs_to_save = 0;
4927 /* lmf_offset is the offset of the LMF from our stack pointer. */
4928 guint32 lmf_offset = cfg->arch.lmf_offset;
4932 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4936 cfg->flags |= MONO_CFG_HAS_CALLS;
4938 sig = mono_method_signature (method);
4939 cfg->code_size = 768 + sig->param_count * 20;
4940 code = cfg->native_code = g_malloc (cfg->code_size);
4943 * compute max_offset in order to use short forward jumps.
4946 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4947 MonoInst *ins = bb->code;
4948 bb->max_offset = max_offset;
4950 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4953 MONO_BB_FOR_EACH_INS (bb, ins)
4954 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4956 if (max_offset > 0xffff)
4957 cfg->arch.long_branch = TRUE;
4960 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4961 * This means that we have to adjust the offsets inside instructions which reference
4962 * arguments received on the stack, since the initial offset doesn't take into
4963 * account spill slots.
4965 mips_adjust_stackframe (cfg);
4967 /* Offset between current sp and the CFA */
4969 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4971 /* stack_offset should not be changed here. */
4972 alloc_size = cfg->stack_offset;
4973 cfg->stack_usage = alloc_size;
4975 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4978 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4980 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4981 fregs_to_save |= (fregs_to_save << 1);
4984 /* If the stack size is too big, save 1024 bytes to start with
4985 * so the prologue can use imm16(reg) addressing, then allocate
4986 * the rest of the frame.
4988 if (alloc_size > ((1 << 15) - 1024)) {
4989 alloc2_size = alloc_size - 1024;
4993 g_assert (mips_is_imm16 (-alloc_size));
4994 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4995 cfa_offset = alloc_size;
4996 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4999 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5000 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5001 if (mips_is_imm16(offset))
5002 mips_sw (code, mips_ra, mips_sp, offset);
5004 g_assert_not_reached ();
5006 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5007 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5010 /* XXX - optimize this later to not save all regs if LMF constructed */
5011 pos = cfg->arch.iregs_offset - alloc2_size;
5013 if (iregs_to_save) {
5014 /* save used registers in own stack frame (at pos) */
5015 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5016 if (iregs_to_save & (1 << i)) {
5017 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5018 g_assert (mips_is_imm16(pos));
5019 MIPS_SW (code, i, mips_sp, pos);
5020 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5021 pos += SIZEOF_REGISTER;
5026 // FIXME: Don't save registers twice if there is an LMF
5027 // s8 has to be special cased since it is overwritten with the updated value
5029 if (method->save_lmf) {
5030 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5031 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5032 g_assert (mips_is_imm16(offset));
5033 if (MIPS_LMF_IREGMASK & (1 << i))
5034 MIPS_SW (code, i, mips_sp, offset);
5039 /* Save float registers */
5040 if (fregs_to_save) {
5041 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5042 if (fregs_to_save & (1 << i)) {
5043 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5044 g_assert (mips_is_imm16(pos));
5045 mips_swc1 (code, i, mips_sp, pos);
5046 pos += sizeof (gulong);
5051 if (method->save_lmf) {
5052 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5053 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5054 g_assert (mips_is_imm16(offset));
5055 mips_swc1 (code, i, mips_sp, offset);
5060 if (cfg->frame_reg != mips_sp) {
5061 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5062 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5064 if (method->save_lmf) {
5065 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5066 g_assert (mips_is_imm16(offset));
5067 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5071 /* store runtime generic context */
5072 if (cfg->rgctx_var) {
5073 MonoInst *ins = cfg->rgctx_var;
5075 g_assert (ins->opcode == OP_REGOFFSET);
5077 g_assert (mips_is_imm16 (ins->inst_offset));
5078 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5081 /* load arguments allocated to register from the stack */
5084 if (!cfg->arch.cinfo)
5085 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
5086 cinfo = cfg->arch.cinfo;
5088 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5089 ArgInfo *ainfo = &cinfo->ret;
5090 inst = cfg->vret_addr;
5091 if (inst->opcode == OP_REGVAR)
5092 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5093 else if (mips_is_imm16 (inst->inst_offset)) {
5094 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5096 mips_load_const (code, mips_at, inst->inst_offset);
5097 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5098 mips_sw (code, ainfo->reg, mips_at, 0);
5102 if (sig->call_convention == MONO_CALL_VARARG) {
5103 ArgInfo *cookie = &cinfo->sig_cookie;
5104 int offset = alloc_size + cookie->offset;
5106 /* Save the sig cookie address */
5107 g_assert (cookie->storage == ArgOnStack);
5109 g_assert (mips_is_imm16(offset));
5110 mips_addi (code, mips_at, cfg->frame_reg, offset);
5111 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5114 /* Keep this in sync with emit_load_volatile_arguments */
5115 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5116 ArgInfo *ainfo = cinfo->args + i;
5117 inst = cfg->args [pos];
5119 if (cfg->verbose_level > 2)
5120 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5121 if (inst->opcode == OP_REGVAR) {
5122 /* Argument ends up in a register */
5123 if (ainfo->storage == ArgInIReg)
5124 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5125 else if (ainfo->storage == ArgInFReg) {
5126 g_assert_not_reached();
5128 ppc_fmr (code, inst->dreg, ainfo->reg);
5131 else if (ainfo->storage == ArgOnStack) {
5132 int offset = cfg->stack_usage + ainfo->offset;
5133 g_assert (mips_is_imm16(offset));
5134 mips_lw (code, inst->dreg, mips_sp, offset);
5136 g_assert_not_reached ();
5138 if (cfg->verbose_level > 2)
5139 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5141 /* Argument ends up on the stack */
5142 if (ainfo->storage == ArgInIReg) {
5144 /* Incoming parameters should be above this frame */
5145 if (cfg->verbose_level > 2)
5146 g_print ("stack slot at %d of %d+%d\n",
5147 inst->inst_offset, alloc_size, alloc2_size);
5148 /* g_assert (inst->inst_offset >= alloc_size); */
5149 g_assert (inst->inst_basereg == cfg->frame_reg);
5150 basereg_offset = inst->inst_offset - alloc2_size;
5151 g_assert (mips_is_imm16 (basereg_offset));
5152 switch (ainfo->size) {
5154 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5157 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5161 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5164 #if (SIZEOF_REGISTER == 4)
5165 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5166 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5167 #elif (SIZEOF_REGISTER == 8)
5168 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5172 g_assert_not_reached ();
5175 } else if (ainfo->storage == ArgOnStack) {
5177 * Argument comes in on the stack, and ends up on the stack
5178 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5179 * 8 and 16 bit quantities. Shorten them in place.
5181 g_assert (mips_is_imm16 (inst->inst_offset));
5182 switch (ainfo->size) {
5184 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5185 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5188 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5189 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5196 g_assert_not_reached ();
5198 } else if (ainfo->storage == ArgInFReg) {
5199 g_assert (mips_is_imm16 (inst->inst_offset));
5200 g_assert (mips_is_imm16 (inst->inst_offset+4));
5201 if (ainfo->size == 8) {
5202 #if _MIPS_SIM == _ABIO32
5203 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5204 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5205 #elif _MIPS_SIM == _ABIN32
5206 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5209 else if (ainfo->size == 4)
5210 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5212 g_assert_not_reached ();
5213 } else if (ainfo->storage == ArgStructByVal) {
5215 int doffset = inst->inst_offset;
5217 g_assert (mips_is_imm16 (inst->inst_offset));
5218 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5219 /* Push the argument registers into their stack slots */
5220 for (i = 0; i < ainfo->size; ++i) {
5221 g_assert (mips_is_imm16(doffset));
5222 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5223 doffset += SIZEOF_REGISTER;
5225 } else if (ainfo->storage == ArgStructByAddr) {
5226 g_assert (mips_is_imm16 (inst->inst_offset));
5227 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5228 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5230 g_assert_not_reached ();
5235 if (method->save_lmf) {
5236 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5237 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5239 if (lmf_pthread_key != -1) {
5240 g_assert_not_reached();
5242 emit_tls_access (code, mips_temp, lmf_pthread_key);
5244 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5245 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5246 g_assert (mips_is_imm16(offset));
5247 mips_addiu (code, mips_a0, mips_temp, offset);
5250 /* This can/will clobber the a0-a3 registers */
5251 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5254 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5255 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5256 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5257 /* new_lmf->previous_lmf = *lmf_addr */
5258 mips_lw (code, mips_at, mips_v0, 0);
5259 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5260 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5261 /* *(lmf_addr) = sp + lmf_offset */
5262 g_assert (mips_is_imm16(lmf_offset));
5263 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5264 mips_sw (code, mips_at, mips_v0, 0);
5266 /* save method info */
5267 mips_load_const (code, mips_at, method);
5268 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5269 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5271 /* save the current IP */
5272 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5273 mips_load_const (code, mips_at, 0x01010101);
5274 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5278 if (mips_is_imm16 (-alloc2_size)) {
5279 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5282 mips_load_const (code, mips_at, -alloc2_size);
5283 mips_addu (code, mips_sp, mips_sp, mips_at);
5285 alloc_size += alloc2_size;
5286 cfa_offset += alloc2_size;
5287 if (cfg->frame_reg != mips_sp)
5288 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5290 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5294 #if _MIPS_SIM == _ABIO32
5295 cfg->arch.tracing_offset = cfg->stack_offset;
5296 #elif _MIPS_SIM == _ABIN32
5297 /* no stack slots by default for argument regs, reserve a special block */
5298 g_assert_not_reached ();
5300 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5303 cfg->code_len = code - cfg->native_code;
5304 g_assert (cfg->code_len < cfg->code_size);
5318 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5321 int save_mode = SAVE_NONE;
5323 MonoMethod *method = cfg->method;
5324 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type;
5325 int save_offset = MIPS_STACK_PARAM_OFFSET;
5327 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5329 offset = code - cfg->native_code;
5330 /* we need about 16 instructions */
5331 if (offset > (cfg->code_size - 16 * 4)) {
5332 cfg->code_size *= 2;
5333 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5334 code = cfg->native_code + offset;
5339 case MONO_TYPE_VOID:
5340 /* special case string .ctor icall */
5341 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5342 save_mode = SAVE_ONE;
5344 save_mode = SAVE_NONE;
5348 save_mode = SAVE_FP;
5350 case MONO_TYPE_VALUETYPE:
5351 save_mode = SAVE_STRUCT;
5355 #if SIZEOF_REGISTER == 4
5356 save_mode = SAVE_TWO;
5357 #elif SIZEOF_REGISTER == 8
5358 save_mode = SAVE_ONE;
5362 save_mode = SAVE_ONE;
5366 mips_addiu (code, mips_sp, mips_sp, -32);
5367 g_assert (mips_is_imm16(save_offset));
5368 switch (save_mode) {
5370 mips_sw (code, mips_v0, mips_sp, save_offset);
5371 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5372 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5373 if (enable_arguments) {
5374 MIPS_MOVE (code, mips_a1, mips_v0);
5375 MIPS_MOVE (code, mips_a2, mips_v1);
5379 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5380 if (enable_arguments) {
5381 MIPS_MOVE (code, mips_a1, mips_v0);
5385 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5386 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5387 mips_lw (code, mips_a0, mips_sp, save_offset);
5388 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5389 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5396 mips_load_const (code, mips_a0, cfg->method);
5397 mips_call (code, mips_t9, func);
5399 switch (save_mode) {
5401 mips_lw (code, mips_v0, mips_sp, save_offset);
5402 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5403 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5406 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5409 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5416 mips_addiu (code, mips_sp, mips_sp, 32);
5423 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5425 MonoMethod *method = cfg->method;
5427 int max_epilog_size = 16 + 20*4;
5428 int alloc2_size = 0;
5429 guint32 iregs_to_restore;
5431 guint32 fregs_to_restore;
5434 if (cfg->method->save_lmf)
5435 max_epilog_size += 128;
5437 if (mono_jit_trace_calls != NULL)
5438 max_epilog_size += 50;
5440 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5441 max_epilog_size += 50;
5444 pos = code - cfg->native_code;
5445 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5446 cfg->code_size *= 2;
5447 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5448 cfg->stat_code_reallocs++;
5452 * Keep in sync with OP_JMP
5455 code = cfg->native_code + pos;
5457 code = cfg->native_code + cfg->code_len;
5459 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5460 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5462 if (cfg->frame_reg != mips_sp) {
5463 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5465 /* If the stack frame is really large, deconstruct it in two steps */
5466 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5467 alloc2_size = cfg->stack_usage - 1024;
5468 /* partially deconstruct the stack */
5469 mips_load_const (code, mips_at, alloc2_size);
5470 mips_addu (code, mips_sp, mips_sp, mips_at);
5472 pos = cfg->arch.iregs_offset - alloc2_size;
5473 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5474 if (iregs_to_restore) {
5475 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5476 if (iregs_to_restore & (1 << i)) {
5477 g_assert (mips_is_imm16(pos));
5478 MIPS_LW (code, i, mips_sp, pos);
5479 pos += SIZEOF_REGISTER;
5486 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5488 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5489 fregs_to_restore |= (fregs_to_restore << 1);
5491 if (fregs_to_restore) {
5492 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5493 if (fregs_to_restore & (1 << i)) {
5494 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5495 g_assert (mips_is_imm16(pos));
5496 mips_lwc1 (code, i, mips_sp, pos);
5503 /* Unlink the LMF if necessary */
5504 if (method->save_lmf) {
5505 int lmf_offset = cfg->arch.lmf_offset;
5507 /* t0 = current_lmf->previous_lmf */
5508 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5509 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5511 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5512 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5513 /* (*lmf_addr) = previous_lmf */
5514 mips_sw (code, mips_temp, mips_t1, 0);
5518 /* Restore the fp */
5519 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5522 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5523 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5524 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5526 /* Restore the stack pointer */
5527 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5528 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5530 /* Caller will emit either return or tail-call sequence */
5532 cfg->code_len = code - cfg->native_code;
5534 g_assert (cfg->code_len < cfg->code_size);
5539 mono_arch_emit_epilog (MonoCompile *cfg)
5543 code = mono_arch_emit_epilog_sub (cfg, NULL);
5545 mips_jr (code, mips_ra);
5548 cfg->code_len = code - cfg->native_code;
5550 g_assert (cfg->code_len < cfg->code_size);
5553 /* remove once throw_exception_by_name is eliminated */
5556 exception_id_by_name (const char *name)
5558 if (strcmp (name, "IndexOutOfRangeException") == 0)
5559 return MONO_EXC_INDEX_OUT_OF_RANGE;
5560 if (strcmp (name, "OverflowException") == 0)
5561 return MONO_EXC_OVERFLOW;
5562 if (strcmp (name, "ArithmeticException") == 0)
5563 return MONO_EXC_ARITHMETIC;
5564 if (strcmp (name, "DivideByZeroException") == 0)
5565 return MONO_EXC_DIVIDE_BY_ZERO;
5566 if (strcmp (name, "InvalidCastException") == 0)
5567 return MONO_EXC_INVALID_CAST;
5568 if (strcmp (name, "NullReferenceException") == 0)
5569 return MONO_EXC_NULL_REF;
5570 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5571 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5572 if (strcmp (name, "ArgumentException") == 0)
5573 return MONO_EXC_ARGUMENT;
5574 g_error ("Unknown intrinsic exception %s\n", name);
5580 mono_arch_emit_exceptions (MonoCompile *cfg)
5583 MonoJumpInfo *patch_info;
5586 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5587 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5588 int max_epilog_size = 50;
5590 /* count the number of exception infos */
5593 * make sure we have enough space for exceptions
5594 * 24 is the simulated call to throw_exception_by_name
5596 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5598 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5599 i = exception_id_by_name (patch_info->data.target);
5600 g_assert (i < MONO_EXC_INTRINS_NUM);
5601 if (!exc_throw_found [i]) {
5602 max_epilog_size += 12;
5603 exc_throw_found [i] = TRUE;
5609 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5610 cfg->code_size *= 2;
5611 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5612 cfg->stat_code_reallocs++;
5615 code = cfg->native_code + cfg->code_len;
5617 /* add code to raise exceptions */
5618 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5619 switch (patch_info->type) {
5620 case MONO_PATCH_INFO_EXC: {
5622 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5624 i = exception_id_by_name (patch_info->data.target);
5625 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5626 if (!exc_throw_pos [i]) {
5629 exc_throw_pos [i] = code;
5630 //g_print ("exc: writing stub at %p\n", code);
5631 mips_load_const (code, mips_a0, patch_info->data.target);
5632 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5633 mips_load_const (code, mips_t9, addr);
5634 mips_jr (code, mips_t9);
5637 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5639 /* Turn into a Relative patch, pointing at code stub */
5640 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5641 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5643 g_assert_not_reached();
5653 cfg->code_len = code - cfg->native_code;
5655 g_assert (cfg->code_len < cfg->code_size);
5660 * Thread local storage support
5663 setup_tls_access (void)
5666 //guint32 *ins, *code;
5668 if (tls_mode == TLS_MODE_FAILED)
5671 if (g_getenv ("MONO_NO_TLS")) {
5672 tls_mode = TLS_MODE_FAILED;
5676 if (tls_mode == TLS_MODE_DETECT) {
5678 tls_mode = TLS_MODE_FAILED;
5682 ins = (guint32*)pthread_getspecific;
5683 /* uncond branch to the real method */
5684 if ((*ins >> 26) == 18) {
5686 val = (*ins & ~3) << 6;
5690 ins = (guint32*)val;
5692 ins = (guint32*) ((char*)ins + val);
5695 code = &cmplwi_1023;
5696 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5698 ppc_li (code, ppc_r4, 0x48);
5701 if (*ins == cmplwi_1023) {
5702 int found_lwz_284 = 0;
5703 for (ptk = 0; ptk < 20; ++ptk) {
5705 if (!*ins || *ins == blr_ins)
5707 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5712 if (!found_lwz_284) {
5713 tls_mode = TLS_MODE_FAILED;
5716 tls_mode = TLS_MODE_LTHREADS;
5717 } else if (*ins == li_0x48) {
5719 /* uncond branch to the real method */
5720 if ((*ins >> 26) == 18) {
5722 val = (*ins & ~3) << 6;
5726 ins = (guint32*)val;
5728 ins = (guint32*) ((char*)ins + val);
5731 ppc_li (code, ppc_r0, 0x7FF2);
5732 if (ins [1] == val) {
5733 /* Darwin on G4, implement */
5734 tls_mode = TLS_MODE_FAILED;
5738 ppc_mfspr (code, ppc_r3, 104);
5739 if (ins [1] != val) {
5740 tls_mode = TLS_MODE_FAILED;
5743 tls_mode = TLS_MODE_DARWIN_G5;
5746 tls_mode = TLS_MODE_FAILED;
5750 tls_mode = TLS_MODE_FAILED;
5755 if (monodomain_key == -1) {
5756 ptk = mono_domain_get_tls_key ();
5758 monodomain_key = ptk;
5760 if (lmf_pthread_key == -1) {
5761 ptk = mono_jit_tls_id;
5763 /*g_print ("MonoLMF at: %d\n", ptk);*/
5764 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5765 init_tls_failed = 1;
5768 lmf_pthread_key = ptk;
5771 if (monothread_key == -1) {
5772 ptk = mono_thread_get_tls_key ();
5774 monothread_key = ptk;
5775 /*g_print ("thread inited: %d\n", ptk);*/
5777 /*g_print ("thread not inited yet %d\n", ptk);*/
5783 mono_arch_finish_init (void)
5785 setup_tls_access ();
5789 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5794 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5796 int this_dreg = mips_a0;
5799 this_dreg = mips_a1;
5801 /* add the this argument */
5802 if (this_reg != -1) {
5804 MONO_INST_NEW (cfg, this, OP_MOVE);
5805 this->type = this_type;
5806 this->sreg1 = this_reg;
5807 this->dreg = mono_alloc_ireg (cfg);
5808 mono_bblock_add_inst (cfg->cbb, this);
5809 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5814 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5815 vtarg->type = STACK_MP;
5816 vtarg->sreg1 = vt_reg;
5817 vtarg->dreg = mono_alloc_ireg (cfg);
5818 mono_bblock_add_inst (cfg->cbb, vtarg);
5819 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5824 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5826 MonoInst *ins = NULL;
5832 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5838 mono_arch_print_tree (MonoInst *tree, int arity)
5843 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5847 setup_tls_access ();
5848 if (monodomain_key == -1)
5851 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5852 ins->inst_offset = monodomain_key;
5857 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5859 return ctx->sc_regs [reg];
5862 #ifdef MONO_ARCH_HAVE_IMT
5864 #define ENABLE_WRONG_METHOD_CHECK 0
5866 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5867 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5869 #define LOADSTORE_SIZE 4
5870 #define JUMP_IMM_SIZE 16
5871 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5872 #define LOAD_CONST_SIZE 8
5873 #define JUMP_JR_SIZE 8
5876 * LOCKING: called with the domain lock held
5879 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5880 gpointer fail_tramp)
5884 guint8 *code, *start, *patch;
5886 for (i = 0; i < count; ++i) {
5887 MonoIMTCheckItem *item = imt_entries [i];
5889 if (item->is_equals) {
5890 if (item->check_target_idx) {
5891 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5892 if (item->has_target_code)
5893 item->chunk_size += LOAD_CONST_SIZE;
5895 item->chunk_size += LOADSTORE_SIZE;
5898 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5899 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5900 if (!item->has_target_code)
5901 item->chunk_size += LOADSTORE_SIZE;
5903 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5904 #if ENABLE_WRONG_METHOD_CHECK
5905 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5910 item->chunk_size += CMP_SIZE + BR_SIZE;
5911 imt_entries [item->check_target_idx]->compare_done = TRUE;
5913 size += item->chunk_size;
5915 /* the initial load of the vtable address */
5916 size += MIPS_LOAD_SEQUENCE_LENGTH;
5918 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5920 code = mono_domain_code_reserve (domain, size);
5924 /* t7 points to the vtable */
5925 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5927 for (i = 0; i < count; ++i) {
5928 MonoIMTCheckItem *item = imt_entries [i];
5930 item->code_target = code;
5931 if (item->is_equals) {
5932 if (item->check_target_idx) {
5933 mips_load_const (code, mips_temp, (gsize)item->key);
5934 item->jmp_code = code;
5935 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5937 if (item->has_target_code) {
5938 mips_load_const (code, mips_t9,
5939 item->value.target_code);
5942 mips_lw (code, mips_t9, mips_t7,
5943 (sizeof (gpointer) * item->value.vtable_slot));
5945 mips_jr (code, mips_t9);
5949 mips_load_const (code, mips_temp, (gsize)item->key);
5951 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5953 if (item->has_target_code) {
5954 mips_load_const (code, mips_t9,
5955 item->value.target_code);
5958 mips_load_const (code, mips_at,
5959 & (vtable->vtable [item->value.vtable_slot]));
5960 mips_lw (code, mips_t9, mips_at, 0);
5962 mips_jr (code, mips_t9);
5964 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5965 mips_load_const (code, mips_t9, fail_tramp);
5966 mips_jr (code, mips_t9);
5969 /* enable the commented code to assert on wrong method */
5970 #if ENABLE_WRONG_METHOD_CHECK
5971 ppc_load (code, ppc_r0, (guint32)item->key);
5972 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5974 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5976 mips_lw (code, mips_t9, mips_t7,
5977 (sizeof (gpointer) * item->value.vtable_slot));
5978 mips_jr (code, mips_t9);
5981 #if ENABLE_WRONG_METHOD_CHECK
5982 ppc_patch (patch, code);
5988 mips_load_const (code, mips_temp, (gulong)item->key);
5989 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5991 item->jmp_code = code;
5992 mips_beq (code, mips_temp, mips_zero, 0);
5996 /* patch the branches to get to the target items */
5997 for (i = 0; i < count; ++i) {
5998 MonoIMTCheckItem *item = imt_entries [i];
5999 if (item->jmp_code && item->check_target_idx) {
6000 mips_patch ((guint32 *)item->jmp_code,
6001 (guint32)imt_entries [item->check_target_idx]->code_target);
6006 mono_stats.imt_thunks_size += code - start;
6007 g_assert (code - start <= size);
6008 mono_arch_flush_icache (start, size);
6013 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6015 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6020 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6022 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6025 /* Soft Debug support */
6026 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6029 * mono_arch_set_breakpoint:
6031 * See mini-amd64.c for docs.
6034 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6037 guint32 addr = (guint32)bp_trigger_page;
6039 mips_load_const (code, mips_t9, addr);
6040 mips_lw (code, mips_t9, mips_t9, 0);
6042 mono_arch_flush_icache (ip, code - ip);
6046 * mono_arch_clear_breakpoint:
6048 * See mini-amd64.c for docs.
6051 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6059 mono_arch_flush_icache (ip, code - ip);
6063 * mono_arch_start_single_stepping:
6065 * See mini-amd64.c for docs.
6068 mono_arch_start_single_stepping (void)
6070 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6074 * mono_arch_stop_single_stepping:
6076 * See mini-amd64.c for docs.
6079 mono_arch_stop_single_stepping (void)
6081 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6085 * mono_arch_is_single_step_event:
6087 * See mini-amd64.c for docs.
6090 mono_arch_is_single_step_event (void *info, void *sigctx)
6092 siginfo_t* sinfo = (siginfo_t*) info;
6093 /* Sometimes the address is off by 4 */
6094 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6101 * mono_arch_is_breakpoint_event:
6103 * See mini-amd64.c for docs.
6106 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6108 siginfo_t* sinfo = (siginfo_t*) info;
6109 /* Sometimes the address is off by 4 */
6110 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6117 * mono_arch_skip_breakpoint:
6119 * See mini-amd64.c for docs.
6122 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6124 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6128 * mono_arch_skip_single_step:
6130 * See mini-amd64.c for docs.
6133 mono_arch_skip_single_step (MonoContext *ctx)
6135 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6139 * mono_arch_get_seq_point_info:
6141 * See mini-amd64.c for docs.
6144 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6150 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */