3 * MIPS backend for the Mono code generator
6 * Mark Mason (mason@broadcom.com)
8 * Based on mini-ppc.c by
9 * Paolo Molaro (lupus@ximian.com)
10 * Dietmar Maurer (dietmar@ximian.com)
13 * (C) 2003 Ximian, Inc.
17 #include <asm/cachectl.h>
19 #include <mono/metadata/abi-details.h>
20 #include <mono/metadata/appdomain.h>
21 #include <mono/metadata/debug-helpers.h>
22 #include <mono/utils/mono-mmap.h>
23 #include <mono/utils/mono-hwcap.h>
24 #include <mono/utils/unlocked.h>
26 #include <mono/arch/mips/mips-codegen.h>
28 #include "mini-mips.h"
31 #include "aot-runtime.h"
32 #include "mini-runtime.h"
34 #define SAVE_FP_REGS 0
36 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
38 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
39 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
40 remember to update cpu-mips.md if you change this */
42 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
43 #define mips_call(c,D,v) do { \
44 guint32 _target = (guint32)(v); \
45 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
46 mips_load_const (c, D, _target); \
47 mips_jalr (c, D, mips_ra); \
50 mips_jumpl (c, _target >> 2); \
62 /* This mutex protects architecture specific caches */
63 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
64 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
65 static mono_mutex_t mini_arch_mutex
;
67 /* Whenever the host is little-endian */
68 static int little_endian
;
69 /* Index of ms word/register */
70 static int ls_word_idx
;
71 /* Index of ls word/register */
72 static int ms_word_idx
;
73 /* Same for offsets */
74 static int ls_word_offset
;
75 static int ms_word_offset
;
78 * The code generated for sequence points reads from this location, which is
79 * made read-only when single stepping is enabled.
81 static gpointer ss_trigger_page
;
83 /* Enabled breakpoints read from this trigger page */
84 static gpointer bp_trigger_page
;
87 #define DEBUG(a) if (cfg->verbose_level > 1) a
93 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
95 code = mips_emit_exc_by_name (code, exc_name); \
96 cfg->bb_exit->max_offset += 16; \
99 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
101 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
102 inst->type = STACK_R8; \
104 inst->inst_p0 = (void*)(addr); \
105 mono_bblock_add_inst (cfg->cbb, inst); \
108 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
109 || ((ins)->opcode == OP_ICOMPARE) \
110 || ((ins)->opcode == OP_LCOMPARE)))
111 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
112 || ((ins)->opcode == OP_ICOMPARE_IMM) \
113 || ((ins)->opcode == OP_LCOMPARE_IMM)))
115 #define INS_REWRITE(ins, op, _s1, _s2) do { \
118 ins->opcode = (op); \
123 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
125 ins->opcode = (op); \
127 ins->inst_imm = (_imm); \
131 typedef struct InstList InstList
;
149 guint16 vtsize
; /* in param area */
152 guint8 size
: 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
161 gboolean vtype_retaddr
;
170 void patch_lui_addiu(guint32
*ip
, guint32 val
);
172 guint8
*mono_arch_emit_epilog_sub (MonoCompile
*cfg
);
173 guint8
*mips_emit_cond_branch (MonoCompile
*cfg
, guint8
*code
, int op
, MonoInst
*ins
);
174 void mips_adjust_stackframe(MonoCompile
*cfg
);
175 void mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
, int this_reg
, int this_type
, int vt_reg
);
176 MonoInst
*mono_arch_get_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
);
179 /* Not defined in asm/cachectl.h */
180 int cacheflush(char *addr
, int nbytes
, int cache
);
183 mono_arch_flush_icache (guint8
*code
, gint size
)
185 /* Linux/MIPS specific */
186 cacheflush ((char*)code
, size
, BCACHE
);
190 mono_arch_flush_register_windows (void)
195 mono_arch_is_inst_imm (int opcode
, int imm_opcode
, gint64 imm
)
201 mips_emit_exc_by_name(guint8
*code
, const char *name
)
204 MonoClass
*exc_class
;
206 exc_class
= mono_class_load_from_name (mono_defaults
.corlib
, "System", name
);
208 mips_load_const (code
, mips_a0
, m_class_get_type_token (exc_class
));
209 addr
= mono_get_throw_corlib_exception ();
210 mips_call (code
, mips_t9
, addr
);
215 mips_emit_load_const (guint8
*code
, int dreg
, target_mgreg_t v
)
217 if (mips_is_imm16 (v
))
218 mips_addiu (code
, dreg
, mips_zero
, ((guint32
)v
) & 0xffff);
220 #if SIZEOF_REGISTER == 8
222 /* v is not a sign-extended 32-bit value */
223 mips_lui (code
, dreg
, mips_zero
, (guint32
)((v
>> (32+16)) & 0xffff));
224 mips_ori (code
, dreg
, dreg
, (guint32
)((v
>> (32)) & 0xffff));
225 mips_dsll (code
, dreg
, dreg
, 16);
226 mips_ori (code
, dreg
, dreg
, (guint32
)((v
>> (16)) & 0xffff));
227 mips_dsll (code
, dreg
, dreg
, 16);
228 mips_ori (code
, dreg
, dreg
, (guint32
)(v
& 0xffff));
232 if (((guint32
)v
) & (1 << 15)) {
233 mips_lui (code
, dreg
, mips_zero
, (((guint32
)v
)>>16)+1);
236 mips_lui (code
, dreg
, mips_zero
, (((guint32
)v
)>>16));
238 if (((guint32
)v
) & 0xffff)
239 mips_addiu (code
, dreg
, dreg
, ((guint32
)v
) & 0xffff);
245 mips_emit_cond_branch (MonoCompile
*cfg
, guint8
*code
, int op
, MonoInst
*ins
)
248 if (cfg
->arch
.long_branch
) {
251 /* Invert test and emit branch around jump */
254 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, br_offset
);
258 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, br_offset
);
262 mips_bltz (code
, ins
->sreg1
, br_offset
);
266 mips_blez (code
, ins
->sreg1
, br_offset
);
270 mips_bgtz (code
, ins
->sreg1
, br_offset
);
274 mips_bgez (code
, ins
->sreg1
, br_offset
);
278 g_assert_not_reached ();
280 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
281 MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
282 mips_lui (code
, mips_at
, mips_zero
, 0);
283 mips_addiu (code
, mips_at
, mips_at
, 0);
284 mips_jr (code
, mips_at
);
288 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
289 MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
292 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, 0);
296 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, 0);
300 mips_bgez (code
, ins
->sreg1
, 0);
304 mips_bgtz (code
, ins
->sreg1
, 0);
308 mips_blez (code
, ins
->sreg1
, 0);
312 mips_bltz (code
, ins
->sreg1
, 0);
316 g_assert_not_reached ();
322 /* XXX - big-endian dependent? */
324 patch_lui_addiu(guint32
*ip
, guint32 val
)
326 guint16
*__lui_addiu
= (guint16
*)(void *)(ip
);
329 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
330 ip
, ((guint32
*)ip
)[0], ((guint32
*)ip
)[1], val
);
333 if (((guint32
)(val
)) & (1 << 15))
334 __lui_addiu
[MINI_LS_WORD_IDX
] = ((((guint32
)(val
)) >> 16) & 0xffff) + 1;
336 __lui_addiu
[MINI_LS_WORD_IDX
] = (((guint32
)(val
)) >> 16) & 0xffff;
337 __lui_addiu
[MINI_LS_WORD_IDX
+ 2] = ((guint32
)(val
)) & 0xffff;
338 mono_arch_flush_icache ((guint8
*)ip
, 8);
343 mips_patch (guint32
*code
, guint32 target
)
346 guint32 op
= ins
>> 26;
347 guint32 diff
, offset
;
349 g_assert (trap_target
!= target
);
350 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
352 case 0x00: /* jr ra */
353 if (ins
== 0x3e00008)
355 g_assert_not_reached ();
359 g_assert (!(target
& 0x03));
360 g_assert ((target
& 0xfc000000) == (((guint32
)code
) & 0xfc000000));
361 ins
= (ins
& 0xfc000000) | (((target
) >> 2) & 0x03ffffff);
363 mono_arch_flush_icache ((guint8
*)code
, 4);
365 case 0x01: /* BLTZ */
368 case 0x06: /* BLEZ */
369 case 0x07: /* BGTZ */
370 case 0x11: /* bc1t */
371 diff
= target
- (guint32
)(code
+ 1);
372 g_assert (((diff
& 0x0003ffff) == diff
) || ((diff
| 0xfffc0000) == diff
));
373 g_assert (!(diff
& 0x03));
374 offset
= ((gint32
)diff
) >> 2;
375 if (((int)offset
) != ((int)(short)offset
))
376 g_assert (((int)offset
) == ((int)(short)offset
));
377 ins
= (ins
& 0xffff0000) | (offset
& 0x0000ffff);
379 mono_arch_flush_icache ((guint8
*)code
, 4);
381 case 0x0f: /* LUI / ADDIU pair */
382 g_assert ((code
[1] >> 26) == 0x9);
383 patch_lui_addiu (code
, target
);
384 mono_arch_flush_icache ((guint8
*)code
, 8);
388 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op
, ins
, code
);
389 g_assert_not_reached ();
393 static void mono_arch_compute_omit_fp (MonoCompile
*cfg
);
396 mono_arch_regname (int reg
) {
397 #if _MIPS_SIM == _ABIO32
398 static const char * rnames
[] = {
399 "zero", "at", "v0", "v1",
400 "a0", "a1", "a2", "a3",
401 "t0", "t1", "t2", "t3",
402 "t4", "t5", "t6", "t7",
403 "s0", "s1", "s2", "s3",
404 "s4", "s5", "s6", "s7",
405 "t8", "t9", "k0", "k1",
406 "gp", "sp", "fp", "ra"
408 #elif _MIPS_SIM == _ABIN32
409 static const char * rnames
[] = {
410 "zero", "at", "v0", "v1",
411 "a0", "a1", "a2", "a3",
412 "a4", "a5", "a6", "a7",
413 "t0", "t1", "t2", "t3",
414 "s0", "s1", "s2", "s3",
415 "s4", "s5", "s6", "s7",
416 "t8", "t9", "k0", "k1",
417 "gp", "sp", "fp", "ra"
420 if (reg
>= 0 && reg
< 32)
426 mono_arch_fregname (int reg
) {
427 static const char * rnames
[] = {
428 "f0", "f1", "f2", "f3",
429 "f4", "f5", "f6", "f7",
430 "f8", "f9", "f10", "f11",
431 "f12", "f13", "f14", "f15",
432 "f16", "f17", "f18", "f19",
433 "f20", "f21", "f22", "f23",
434 "f24", "f25", "f26", "f27",
435 "f28", "f29", "f30", "f31"
437 if (reg
>= 0 && reg
< 32)
442 /* this function overwrites at */
444 emit_memcpy (guint8
*code
, int size
, int dreg
, int doffset
, int sreg
, int soffset
)
446 /* XXX write a loop, not an unrolled loop */
448 mips_lw (code
, mips_at
, sreg
, soffset
);
449 mips_sw (code
, mips_at
, dreg
, doffset
);
458 * mono_arch_get_argument_info:
459 * @csig: a method signature
460 * @param_count: the number of parameters to consider
461 * @arg_info: an array to store the result infos
463 * Gathers information on parameters such as size, alignment and
464 * padding. arg_info should be large enought to hold param_count + 1 entries.
466 * Returns the size of the activation frame.
469 mono_arch_get_argument_info (MonoMethodSignature
*csig
, int param_count
, MonoJitArgumentInfo
*arg_info
)
471 int k
, frame_size
= 0;
472 guint32 size
, align
, pad
;
475 if (MONO_TYPE_ISSTRUCT (csig
->ret
)) {
476 frame_size
+= sizeof (target_mgreg_t
);
480 arg_info
[0].offset
= offset
;
483 frame_size
+= sizeof (target_mgreg_t
);
487 arg_info
[0].size
= frame_size
;
489 for (k
= 0; k
< param_count
; k
++) {
490 size
= mini_type_stack_size_full (csig
->params
[k
], &align
, csig
->pinvoke
);
492 /* ignore alignment for now */
495 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
496 arg_info
[k
].pad
= pad
;
498 arg_info
[k
+ 1].pad
= 0;
499 arg_info
[k
+ 1].size
= size
;
501 arg_info
[k
+ 1].offset
= offset
;
505 align
= MONO_ARCH_FRAME_ALIGNMENT
;
506 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
507 arg_info
[k
].pad
= pad
;
512 /* The delegate object plus 3 params */
513 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
516 get_delegate_invoke_impl (MonoTrampInfo
**info
, gboolean has_target
, gboolean param_count
)
518 guint8
*code
, *start
;
521 start
= code
= mono_global_codeman_reserve (16);
523 /* Replace the this argument with the target */
524 mips_lw (code
, mips_temp
, mips_a0
, MONO_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
525 mips_lw (code
, mips_a0
, mips_a0
, MONO_STRUCT_OFFSET (MonoDelegate
, target
));
526 mips_jr (code
, mips_temp
);
529 g_assert ((code
- start
) <= 16);
531 mono_arch_flush_icache (start
, 16);
532 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE
, NULL
));
536 size
= 16 + param_count
* 4;
537 start
= code
= mono_global_codeman_reserve (size
);
539 mips_lw (code
, mips_temp
, mips_a0
, MONO_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
540 /* slide down the arguments */
541 for (i
= 0; i
< param_count
; ++i
) {
542 mips_move (code
, mips_a0
+ i
, mips_a0
+ i
+ 1);
544 mips_jr (code
, mips_temp
);
547 g_assert ((code
- start
) <= size
);
549 mono_arch_flush_icache (start
, size
);
550 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE
, NULL
));
554 *info
= mono_tramp_info_create ("delegate_invoke_impl_has_target", start
, code
- start
, NULL
, NULL
);
556 char *name
= g_strdup_printf ("delegate_invoke_impl_target_%d", param_count
);
557 *info
= mono_tramp_info_create (name
, start
, code
- start
, NULL
, NULL
);
565 * mono_arch_get_delegate_invoke_impls:
567 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
571 mono_arch_get_delegate_invoke_impls (void)
577 get_delegate_invoke_impl (&info
, TRUE
, 0);
578 res
= g_slist_prepend (res
, info
);
580 for (i
= 0; i
<= MAX_ARCH_DELEGATE_PARAMS
; ++i
) {
581 get_delegate_invoke_impl (&info
, FALSE
, i
);
582 res
= g_slist_prepend (res
, info
);
589 mono_arch_get_delegate_invoke_impl (MonoMethodSignature
*sig
, gboolean has_target
)
591 guint8
*code
, *start
;
593 /* FIXME: Support more cases */
594 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
598 static guint8
* cached
= NULL
;
599 mono_mini_arch_lock ();
601 mono_mini_arch_unlock ();
605 if (mono_ee_features
.use_aot_trampolines
) {
606 start
= mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
609 start
= get_delegate_invoke_impl (&info
, TRUE
, 0);
610 mono_tramp_info_register (info
, NULL
);
613 mono_mini_arch_unlock ();
616 static guint8
* cache
[MAX_ARCH_DELEGATE_PARAMS
+ 1] = {NULL
};
619 if (sig
->param_count
> MAX_ARCH_DELEGATE_PARAMS
)
621 for (i
= 0; i
< sig
->param_count
; ++i
)
622 if (!mono_is_regsize_var (sig
->params
[i
]))
625 mono_mini_arch_lock ();
626 code
= cache
[sig
->param_count
];
628 mono_mini_arch_unlock ();
632 if (mono_ee_features
.use_aot_trampolines
) {
633 char *name
= g_strdup_printf ("delegate_invoke_impl_target_%d", sig
->param_count
);
634 start
= mono_aot_get_trampoline (name
);
638 start
= get_delegate_invoke_impl (&info
, FALSE
, sig
->param_count
);
639 mono_tramp_info_register (info
, NULL
);
641 cache
[sig
->param_count
] = start
;
642 mono_mini_arch_unlock ();
650 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
, int offset
, gboolean load_imt_reg
)
656 mono_arch_get_this_arg_from_call (host_mgreg_t
*regs
, guint8
*code
)
659 return (gpointer
)regs
[mips_a0
];
663 * Initialize the cpu to execute managed code.
666 mono_arch_cpu_init (void)
668 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
677 ls_word_offset
= ls_word_idx
* 4;
678 ms_word_offset
= ms_word_idx
* 4;
682 * Initialize architecture specific code.
685 mono_arch_init (void)
687 mono_os_mutex_init_recursive (&mini_arch_mutex
);
689 ss_trigger_page
= mono_valloc (NULL
, mono_pagesize (), MONO_MMAP_READ
|MONO_MMAP_32BIT
, MONO_MEM_ACCOUNT_OTHER
);
690 bp_trigger_page
= mono_valloc (NULL
, mono_pagesize (), MONO_MMAP_READ
|MONO_MMAP_32BIT
, MONO_MEM_ACCOUNT_OTHER
);
691 mono_mprotect (bp_trigger_page
, mono_pagesize (), 0);
695 * Cleanup architecture specific code.
698 mono_arch_cleanup (void)
700 mono_os_mutex_destroy (&mini_arch_mutex
);
704 mono_arch_have_fast_tls (void)
710 * This function returns the optimizations supported on this cpu.
713 mono_arch_cpu_optimizations (guint32
*exclude_mask
)
717 /* no mips-specific optimizations yet */
723 * This function test for all SIMD functions supported.
725 * Returns a bitmask corresponding to all supported versions.
729 mono_arch_cpu_enumerate_simd_versions (void)
731 /* SIMD is currently unimplemented */
736 mono_arch_get_allocatable_int_vars (MonoCompile
*cfg
)
741 for (i
= 0; i
< cfg
->num_varinfo
; i
++) {
742 MonoInst
*ins
= cfg
->varinfo
[i
];
743 MonoMethodVar
*vmv
= MONO_VARINFO (cfg
, i
);
746 if (vmv
->range
.first_use
.abs_pos
>= vmv
->range
.last_use
.abs_pos
)
749 if (ins
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
) || (ins
->opcode
!= OP_LOCAL
&& ins
->opcode
!= OP_ARG
))
752 /* we can only allocate 32 bit values */
753 if (mono_is_regsize_var (ins
->inst_vtype
)) {
754 g_assert (MONO_VARINFO (cfg
, i
)->reg
== -1);
755 g_assert (i
== vmv
->idx
);
756 vars
= mono_varlist_insert_sorted (cfg
, vars
, vmv
, FALSE
);
764 mono_arch_get_global_int_regs (MonoCompile
*cfg
)
768 regs
= g_list_prepend (regs
, (gpointer
)mips_s0
);
769 regs
= g_list_prepend (regs
, (gpointer
)mips_s1
);
770 regs
= g_list_prepend (regs
, (gpointer
)mips_s2
);
771 regs
= g_list_prepend (regs
, (gpointer
)mips_s3
);
772 regs
= g_list_prepend (regs
, (gpointer
)mips_s4
);
773 //regs = g_list_prepend (regs, (gpointer)mips_s5);
774 regs
= g_list_prepend (regs
, (gpointer
)mips_s6
);
775 regs
= g_list_prepend (regs
, (gpointer
)mips_s7
);
781 * mono_arch_regalloc_cost:
783 * Return the cost, in number of memory references, of the action of
784 * allocating the variable VMV into a register during global register
788 mono_arch_regalloc_cost (MonoCompile
*cfg
, MonoMethodVar
*vmv
)
795 args_onto_stack (CallInfo
*info
)
797 g_assert (!info
->on_stack
);
798 g_assert (info
->stack_size
<= MIPS_STACK_PARAM_OFFSET
);
799 info
->on_stack
= TRUE
;
800 info
->stack_size
= MIPS_STACK_PARAM_OFFSET
;
803 #if _MIPS_SIM == _ABIO32
805 * O32 calling convention version
809 add_int32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
810 /* First, see if we need to drop onto the stack */
811 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
812 args_onto_stack (info
);
814 /* Now, place the argument */
815 if (info
->on_stack
) {
816 ainfo
->storage
= ArgOnStack
;
817 ainfo
->reg
= mips_sp
; /* in the caller */
818 ainfo
->offset
= info
->stack_size
;
821 ainfo
->storage
= ArgInIReg
;
822 ainfo
->reg
= info
->gr
;
824 info
->gr_passed
= TRUE
;
826 info
->stack_size
+= 4;
830 add_int64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
831 /* First, see if we need to drop onto the stack */
832 if (!info
->on_stack
&& info
->gr
+1 > MIPS_LAST_ARG_REG
)
833 args_onto_stack (info
);
835 /* Now, place the argument */
836 if (info
->on_stack
) {
837 g_assert (info
->stack_size
% 4 == 0);
838 info
->stack_size
+= (info
->stack_size
% 8);
840 ainfo
->storage
= ArgOnStack
;
841 ainfo
->reg
= mips_sp
; /* in the caller */
842 ainfo
->offset
= info
->stack_size
;
845 // info->gr must be a0 or a2
846 info
->gr
+= (info
->gr
- MIPS_FIRST_ARG_REG
) % 2;
847 g_assert(info
->gr
<= MIPS_LAST_ARG_REG
);
849 ainfo
->storage
= ArgInIReg
;
850 ainfo
->reg
= info
->gr
;
852 info
->gr_passed
= TRUE
;
854 info
->stack_size
+= 8;
858 add_float32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
859 /* First, see if we need to drop onto the stack */
860 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
861 args_onto_stack (info
);
863 /* Now, place the argument */
864 if (info
->on_stack
) {
865 ainfo
->storage
= ArgOnStack
;
866 ainfo
->reg
= mips_sp
; /* in the caller */
867 ainfo
->offset
= info
->stack_size
;
870 /* Only use FP regs for args if no int args passed yet */
871 if (!info
->gr_passed
&& info
->fr
<= MIPS_LAST_FPARG_REG
) {
872 ainfo
->storage
= ArgInFReg
;
873 ainfo
->reg
= info
->fr
;
874 /* Even though it's a single-precision float, it takes up two FP regs */
876 /* FP and GP slots do not overlap */
880 /* Passing single-precision float arg in a GP register
881 * such as: func (0, 1.0, 2, 3);
882 * In this case, only one 'gr' register is consumed.
884 ainfo
->storage
= ArgInIReg
;
885 ainfo
->reg
= info
->gr
;
888 info
->gr_passed
= TRUE
;
891 info
->stack_size
+= 4;
895 add_float64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
896 /* First, see if we need to drop onto the stack */
897 if (!info
->on_stack
&& info
->gr
+1 > MIPS_LAST_ARG_REG
)
898 args_onto_stack (info
);
900 /* Now, place the argument */
901 if (info
->on_stack
) {
902 g_assert(info
->stack_size
% 4 == 0);
903 info
->stack_size
+= (info
->stack_size
% 8);
905 ainfo
->storage
= ArgOnStack
;
906 ainfo
->reg
= mips_sp
; /* in the caller */
907 ainfo
->offset
= info
->stack_size
;
910 /* Only use FP regs for args if no int args passed yet */
911 if (!info
->gr_passed
&& info
->fr
<= MIPS_LAST_FPARG_REG
) {
912 ainfo
->storage
= ArgInFReg
;
913 ainfo
->reg
= info
->fr
;
915 /* FP and GP slots do not overlap */
919 // info->gr must be a0 or a2
920 info
->gr
+= (info
->gr
- MIPS_FIRST_ARG_REG
) % 2;
921 g_assert(info
->gr
<= MIPS_LAST_ARG_REG
);
923 ainfo
->storage
= ArgInIReg
;
924 ainfo
->reg
= info
->gr
;
926 info
->gr_passed
= TRUE
;
929 info
->stack_size
+= 8;
931 #elif _MIPS_SIM == _ABIN32
933 * N32 calling convention version
937 add_int32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
938 /* First, see if we need to drop onto the stack */
939 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
940 args_onto_stack (info
);
942 /* Now, place the argument */
943 if (info
->on_stack
) {
944 ainfo
->storage
= ArgOnStack
;
945 ainfo
->reg
= mips_sp
; /* in the caller */
946 ainfo
->offset
= info
->stack_size
;
947 info
->stack_size
+= SIZEOF_REGISTER
;
950 ainfo
->storage
= ArgInIReg
;
951 ainfo
->reg
= info
->gr
;
953 info
->gr_passed
= TRUE
;
958 add_int64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
959 /* First, see if we need to drop onto the stack */
960 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
961 args_onto_stack (info
);
963 /* Now, place the argument */
964 if (info
->on_stack
) {
965 g_assert (info
->stack_size
% 4 == 0);
966 info
->stack_size
+= (info
->stack_size
% 8);
968 ainfo
->storage
= ArgOnStack
;
969 ainfo
->reg
= mips_sp
; /* in the caller */
970 ainfo
->offset
= info
->stack_size
;
971 info
->stack_size
+= SIZEOF_REGISTER
;
974 g_assert (info
->gr
<= MIPS_LAST_ARG_REG
);
976 ainfo
->storage
= ArgInIReg
;
977 ainfo
->reg
= info
->gr
;
979 info
->gr_passed
= TRUE
;
984 add_float32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
985 /* First, see if we need to drop onto the stack */
986 if (!info
->on_stack
) {
987 if (info
->gr
> MIPS_LAST_ARG_REG
)
988 args_onto_stack (info
);
989 else if (info
->fr
> MIPS_LAST_FPARG_REG
)
990 args_onto_stack (info
);
993 /* Now, place the argument */
994 if (info
->on_stack
) {
995 ainfo
->storage
= ArgOnStack
;
996 ainfo
->reg
= mips_sp
; /* in the caller */
997 ainfo
->offset
= info
->stack_size
;
998 info
->stack_size
+= FREG_SIZE
;
1001 ainfo
->storage
= ArgInFReg
;
1002 ainfo
->reg
= info
->fr
;
1004 /* FP and GP slots do not overlap */
1010 add_float64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
1011 /* First, see if we need to drop onto the stack */
1012 if (!info
->on_stack
) {
1013 if (info
->gr
> MIPS_LAST_ARG_REG
)
1014 args_onto_stack (info
);
1015 else if (info
->fr
> MIPS_LAST_FPARG_REG
)
1016 args_onto_stack (info
);
1019 /* Now, place the argument */
1020 if (info
->on_stack
) {
1021 g_assert(info
->stack_size
% 4 == 0);
1022 info
->stack_size
+= (info
->stack_size
% 8);
1024 ainfo
->storage
= ArgOnStack
;
1025 ainfo
->reg
= mips_sp
; /* in the caller */
1026 ainfo
->offset
= info
->stack_size
;
1027 info
->stack_size
+= FREG_SIZE
;
1030 ainfo
->storage
= ArgInFReg
;
1031 ainfo
->reg
= info
->fr
;
1033 /* FP and GP slots do not overlap */
1040 get_call_info (MonoMemPool
*mp
, MonoMethodSignature
*sig
)
1043 int n
= sig
->hasthis
+ sig
->param_count
;
1045 MonoType
* simpletype
;
1047 gboolean is_pinvoke
= sig
->pinvoke
;
1050 cinfo
= mono_mempool_alloc0 (mp
, sizeof (CallInfo
) + (sizeof (ArgInfo
) * n
));
1052 cinfo
= g_malloc0 (sizeof (CallInfo
) + (sizeof (ArgInfo
) * n
));
1054 cinfo
->fr
= MIPS_FIRST_FPARG_REG
;
1055 cinfo
->gr
= MIPS_FIRST_ARG_REG
;
1056 cinfo
->stack_size
= 0;
1058 DEBUG(printf("calculate_sizes\n"));
1060 cinfo
->vtype_retaddr
= MONO_TYPE_ISSTRUCT (sig
->ret
) ? TRUE
: FALSE
;
1064 /* handle returning a struct */
1065 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1066 cinfo
->struct_ret
= cinfo
->gr
;
1067 add_int32_arg (cinfo
, &cinfo
->ret
);
1071 add_int32_arg (cinfo
, cinfo
->args
+ n
);
1076 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1077 * the first argument, allowing 'this' to be always passed in the first arg reg.
1078 * Also do this if the first argument is a reference type, since virtual calls
1079 * are sometimes made using calli without sig->hasthis set, like in the delegate
1082 if (cinfo
->vtype_retaddr
&& !is_pinvoke
&& (sig
->hasthis
|| (sig
->param_count
> 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig
->params
[0]))))) {
1084 add_int32_arg (cinfo
, cinfo
->args
+ n
);
1087 add_int32_arg (cinfo
, cinfo
->args
+ sig
->hasthis
);
1091 add_int32_arg (cinfo
, &cinfo
->ret
);
1092 cinfo
->struct_ret
= cinfo
->ret
.reg
;
1096 add_int32_arg (cinfo
, cinfo
->args
+ n
);
1100 if (cinfo
->vtype_retaddr
) {
1101 add_int32_arg (cinfo
, &cinfo
->ret
);
1102 cinfo
->struct_ret
= cinfo
->ret
.reg
;
1107 DEBUG(printf("params: %d\n", sig
->param_count
));
1108 for (i
= pstart
; i
< sig
->param_count
; ++i
) {
1109 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1110 /* Prevent implicit arguments and sig_cookie from
1111 being passed in registers */
1112 args_onto_stack (cinfo
);
1113 /* Emit the signature cookie just before the implicit arguments */
1114 add_int32_arg (cinfo
, &cinfo
->sig_cookie
);
1116 DEBUG(printf("param %d: ", i
));
1117 simpletype
= mini_get_underlying_type (sig
->params
[i
]);
1118 switch (simpletype
->type
) {
1121 DEBUG(printf("1 byte\n"));
1122 cinfo
->args
[n
].size
= 1;
1123 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1128 DEBUG(printf("2 bytes\n"));
1129 cinfo
->args
[n
].size
= 2;
1130 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1135 DEBUG(printf("4 bytes\n"));
1136 cinfo
->args
[n
].size
= 4;
1137 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1143 case MONO_TYPE_FNPTR
:
1144 case MONO_TYPE_OBJECT
:
1145 cinfo
->args
[n
].size
= sizeof (target_mgreg_t
);
1146 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1149 case MONO_TYPE_GENERICINST
:
1150 if (!mono_type_generic_inst_is_valuetype (simpletype
)) {
1151 cinfo
->args
[n
].size
= sizeof (target_mgreg_t
);
1152 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1157 case MONO_TYPE_TYPEDBYREF
:
1158 case MONO_TYPE_VALUETYPE
: {
1161 int has_offset
= FALSE
;
1163 gint size
, alignment
;
1166 if (simpletype
->type
== MONO_TYPE_TYPEDBYREF
) {
1167 size
= MONO_ABI_SIZEOF (MonoTypedRef
);
1168 alignment
= sizeof (target_mgreg_t
);
1170 klass
= mono_class_from_mono_type_internal (sig
->params
[i
]);
1172 size
= mono_class_native_size (klass
, NULL
);
1174 size
= mono_class_value_size (klass
, NULL
);
1175 alignment
= mono_class_min_align (klass
);
1177 #if MIPS_PASS_STRUCTS_BY_VALUE
1178 /* Need to do alignment if struct contains long or double */
1179 if (alignment
> 4) {
1180 /* Drop onto stack *before* looking at
1181 stack_size, if required. */
1182 if (!cinfo
->on_stack
&& cinfo
->gr
> MIPS_LAST_ARG_REG
)
1183 args_onto_stack (cinfo
);
1184 if (cinfo
->stack_size
& (alignment
- 1)) {
1185 add_int32_arg (cinfo
, &dummy_arg
);
1187 g_assert (!(cinfo
->stack_size
& (alignment
- 1)));
1191 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1192 mono_class_native_size (sig
->params
[i
]->data
.klass
, NULL
),
1193 cinfo
->stack_size
, alignment
);
1195 nwords
= (size
+ sizeof (target_mgreg_t
) -1 ) / sizeof (target_mgreg_t
);
1196 g_assert (cinfo
->args
[n
].size
== 0);
1197 g_assert (cinfo
->args
[n
].vtsize
== 0);
1198 for (j
= 0; j
< nwords
; ++j
) {
1200 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1201 if (cinfo
->on_stack
)
1204 add_int32_arg (cinfo
, &dummy_arg
);
1205 if (!has_offset
&& cinfo
->on_stack
) {
1206 cinfo
->args
[n
].offset
= dummy_arg
.offset
;
1210 if (cinfo
->on_stack
)
1211 cinfo
->args
[n
].vtsize
+= 1;
1213 cinfo
->args
[n
].size
+= 1;
1215 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1216 cinfo
->args
[n
].storage
= ArgStructByVal
;
1218 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1219 cinfo
->args
[n
].storage
= ArgStructByAddr
;
1226 DEBUG(printf("8 bytes\n"));
1227 cinfo
->args
[n
].size
= 8;
1228 add_int64_arg (cinfo
, &cinfo
->args
[n
]);
1232 DEBUG(printf("R4\n"));
1233 cinfo
->args
[n
].size
= 4;
1234 add_float32_arg (cinfo
, &cinfo
->args
[n
]);
1238 DEBUG(printf("R8\n"));
1239 cinfo
->args
[n
].size
= 8;
1240 add_float64_arg (cinfo
, &cinfo
->args
[n
]);
1244 g_error ("Can't trampoline 0x%x", sig
->params
[i
]->type
);
1248 /* Handle the case where there are no implicit arguments */
1249 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1250 /* Prevent implicit arguments and sig_cookie from
1251 being passed in registers */
1252 args_onto_stack (cinfo
);
1253 /* Emit the signature cookie just before the implicit arguments */
1254 add_int32_arg (cinfo
, &cinfo
->sig_cookie
);
1258 simpletype
= mini_get_underlying_type (sig
->ret
);
1259 switch (simpletype
->type
) {
1269 case MONO_TYPE_FNPTR
:
1270 case MONO_TYPE_OBJECT
:
1271 cinfo
->ret
.reg
= mips_v0
;
1275 cinfo
->ret
.reg
= mips_v0
;
1279 cinfo
->ret
.reg
= mips_f0
;
1280 cinfo
->ret
.storage
= ArgInFReg
;
1282 case MONO_TYPE_GENERICINST
:
1283 if (!mono_type_generic_inst_is_valuetype (simpletype
)) {
1284 cinfo
->ret
.reg
= mips_v0
;
1288 case MONO_TYPE_VALUETYPE
:
1289 case MONO_TYPE_TYPEDBYREF
:
1291 case MONO_TYPE_VOID
:
1294 g_error ("Can't handle as return value 0x%x", sig
->ret
->type
);
1298 /* align stack size to 16 */
1299 cinfo
->stack_size
= (cinfo
->stack_size
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1301 cinfo
->stack_usage
= cinfo
->stack_size
;
1306 debug_omit_fp (void)
1309 return mono_debug_count ();
1316 * mono_arch_compute_omit_fp:
1317 * Determine whether the frame pointer can be eliminated.
1320 mono_arch_compute_omit_fp (MonoCompile
*cfg
)
1322 MonoMethodSignature
*sig
;
1323 MonoMethodHeader
*header
;
1327 if (cfg
->arch
.omit_fp_computed
)
1330 header
= cfg
->header
;
1332 sig
= mono_method_signature_internal (cfg
->method
);
1334 if (!cfg
->arch
.cinfo
)
1335 cfg
->arch
.cinfo
= get_call_info (cfg
->mempool
, sig
);
1336 cinfo
= cfg
->arch
.cinfo
;
1339 * FIXME: Remove some of the restrictions.
1341 cfg
->arch
.omit_fp
= TRUE
;
1342 cfg
->arch
.omit_fp_computed
= TRUE
;
1344 if (cfg
->disable_omit_fp
)
1345 cfg
->arch
.omit_fp
= FALSE
;
1346 if (!debug_omit_fp ())
1347 cfg
->arch
.omit_fp
= FALSE
;
1348 if (cfg
->method
->save_lmf
)
1349 cfg
->arch
.omit_fp
= FALSE
;
1350 if (cfg
->flags
& MONO_CFG_HAS_ALLOCA
)
1351 cfg
->arch
.omit_fp
= FALSE
;
1352 if (header
->num_clauses
)
1353 cfg
->arch
.omit_fp
= FALSE
;
1354 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
))
1355 cfg
->arch
.omit_fp
= FALSE
;
1357 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1358 * there are stack arguments.
1361 if (cinfo->stack_usage)
1362 cfg->arch.omit_fp = FALSE;
1366 for (i
= cfg
->locals_start
; i
< cfg
->num_varinfo
; i
++) {
1367 MonoInst
*ins
= cfg
->varinfo
[i
];
1370 locals_size
+= mono_type_size (ins
->inst_vtype
, &ialign
);
1373 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1377 * Set var information according to the calling convention. mips version.
1378 * The locals var stuff should most likely be split in another method.
1381 mono_arch_allocate_vars (MonoCompile
*cfg
)
1383 MonoMethodSignature
*sig
;
1384 MonoMethodHeader
*header
;
1386 int i
, offset
, size
, align
, curinst
;
1387 int frame_reg
= mips_sp
;
1388 guint32 iregs_to_save
= 0;
1390 guint32 fregs_to_restore
;
1394 sig
= mono_method_signature_internal (cfg
->method
);
1396 if (!cfg
->arch
.cinfo
)
1397 cfg
->arch
.cinfo
= get_call_info (cfg
->mempool
, sig
);
1398 cinfo
= cfg
->arch
.cinfo
;
1400 mono_arch_compute_omit_fp (cfg
);
1402 /* spill down, we'll fix it in a separate pass */
1403 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1405 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1406 * call convs needs to be handled this way.
1408 if (cfg
->flags
& MONO_CFG_HAS_VARARGS
)
1409 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (target_mgreg_t
)*8);
1411 /* gtk-sharp and other broken code will dllimport vararg functions even with
1412 * non-varargs signatures. Since there is little hope people will get this right
1413 * we assume they won't.
1415 if (cfg
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
1416 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (target_mgreg_t
)*8);
1418 /* a0-a3 always present */
1419 cfg
->param_area
= MAX (cfg
->param_area
, MIPS_STACK_PARAM_OFFSET
);
1421 header
= cfg
->header
;
1423 if (cfg
->arch
.omit_fp
)
1424 frame_reg
= mips_sp
;
1426 frame_reg
= mips_fp
;
1427 cfg
->frame_reg
= frame_reg
;
1428 if (frame_reg
!= mips_sp
) {
1429 cfg
->used_int_regs
|= 1 << frame_reg
;
1434 if (!MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1435 /* FIXME: handle long and FP values */
1436 switch (mini_get_underlying_type (sig
->ret
)->type
) {
1437 case MONO_TYPE_VOID
:
1441 cfg
->ret
->opcode
= OP_REGVAR
;
1442 cfg
->ret
->inst_c0
= cfg
->ret
->dreg
= mips_f0
;
1445 cfg
->ret
->opcode
= OP_REGVAR
;
1446 cfg
->ret
->inst_c0
= mips_v0
;
1450 /* Space for outgoing parameters, including a0-a3 */
1451 offset
+= cfg
->param_area
;
1453 /* Now handle the local variables */
1455 curinst
= cfg
->locals_start
;
1456 for (i
= curinst
; i
< cfg
->num_varinfo
; ++i
) {
1457 inst
= cfg
->varinfo
[i
];
1458 if ((inst
->flags
& MONO_INST_IS_DEAD
) || inst
->opcode
== OP_REGVAR
)
1461 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1462 * pinvoke wrappers when they call functions returning structure
1464 if (inst
->backend
.is_pinvoke
&& MONO_TYPE_ISSTRUCT (inst
->inst_vtype
) && inst
->inst_vtype
->type
!= MONO_TYPE_TYPEDBYREF
)
1465 size
= mono_class_native_size (mono_class_from_mono_type_internal (inst
->inst_vtype
), (unsigned int *) &align
);
1467 size
= mono_type_size (inst
->inst_vtype
, &align
);
1469 offset
+= align
- 1;
1470 offset
&= ~(align
- 1);
1471 inst
->inst_offset
= offset
;
1472 inst
->opcode
= OP_REGOFFSET
;
1473 inst
->inst_basereg
= frame_reg
;
1475 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1478 /* Space for LMF (if needed) */
1479 if (cfg
->method
->save_lmf
) {
1480 /* align the offset to 16 bytes */
1481 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1482 cfg
->arch
.lmf_offset
= offset
;
1483 offset
+= sizeof (MonoLMF
);
1486 if (sig
->call_convention
== MONO_CALL_VARARG
) {
1490 /* Allocate a local slot to hold the sig cookie address */
1491 offset
+= align
- 1;
1492 offset
&= ~(align
- 1);
1493 cfg
->sig_cookie
= offset
;
1497 offset
+= SIZEOF_REGISTER
- 1;
1498 offset
&= ~(SIZEOF_REGISTER
- 1);
1500 /* Space for saved registers */
1501 cfg
->arch
.iregs_offset
= offset
;
1502 iregs_to_save
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
1503 if (iregs_to_save
) {
1504 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
1505 if (iregs_to_save
& (1 << i
)) {
1506 offset
+= SIZEOF_REGISTER
;
1511 /* saved float registers */
1513 fregs_to_restore
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
1514 if (fregs_to_restore
) {
1515 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
1516 if (fregs_to_restore
& (1 << i
)) {
1517 offset
+= sizeof(double);
1523 #if _MIPS_SIM == _ABIO32
1524 /* Now add space for saving the ra */
1525 offset
+= TARGET_SIZEOF_VOID_P
;
1528 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1529 cfg
->stack_offset
= offset
;
1530 cfg
->arch
.local_alloc_offset
= cfg
->stack_offset
;
1534 * Now allocate stack slots for the int arg regs (a0 - a3)
1535 * On MIPS o32, these are just above the incoming stack pointer
1536 * Even if the arg has been assigned to a regvar, it gets a stack slot
1539 /* Return struct-by-value results in a hidden first argument */
1540 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1541 cfg
->vret_addr
->opcode
= OP_REGOFFSET
;
1542 cfg
->vret_addr
->inst_c0
= mips_a0
;
1543 cfg
->vret_addr
->inst_offset
= offset
;
1544 cfg
->vret_addr
->inst_basereg
= frame_reg
;
1545 offset
+= SIZEOF_REGISTER
;
1548 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
1549 inst
= cfg
->args
[i
];
1550 if (inst
->opcode
!= OP_REGVAR
) {
1553 if (sig
->hasthis
&& (i
== 0))
1554 arg_type
= mono_get_object_type ();
1556 arg_type
= sig
->params
[i
- sig
->hasthis
];
1558 inst
->opcode
= OP_REGOFFSET
;
1559 size
= mono_type_size (arg_type
, &align
);
1561 if (size
< SIZEOF_REGISTER
) {
1562 size
= SIZEOF_REGISTER
;
1563 align
= SIZEOF_REGISTER
;
1565 inst
->inst_basereg
= frame_reg
;
1566 offset
= (offset
+ align
- 1) & ~(align
- 1);
1567 inst
->inst_offset
= offset
;
1569 if (cfg
->verbose_level
> 1)
1570 printf ("allocating param %d to fp[%d]\n", i
, inst
->inst_offset
);
1573 #if _MIPS_SIM == _ABIO32
1574 /* o32: Even a0-a3 get stack slots */
1575 size
= SIZEOF_REGISTER
;
1576 align
= SIZEOF_REGISTER
;
1577 inst
->inst_basereg
= frame_reg
;
1578 offset
= (offset
+ align
- 1) & ~(align
- 1);
1579 inst
->inst_offset
= offset
;
1581 if (cfg
->verbose_level
> 1)
1582 printf ("allocating param %d to fp[%d]\n", i
, inst
->inst_offset
);
1586 #if _MIPS_SIM == _ABIN32
1587 /* Now add space for saving the ra */
1588 offset
+= TARGET_SIZEOF_VOID_P
;
1591 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1592 cfg
->stack_offset
= offset
;
1593 cfg
->arch
.local_alloc_offset
= cfg
->stack_offset
;
1598 mono_arch_create_vars (MonoCompile
*cfg
)
1600 MonoMethodSignature
*sig
;
1602 sig
= mono_method_signature_internal (cfg
->method
);
1604 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1605 cfg
->vret_addr
= mono_compile_create_var (cfg
, mono_get_int_type (), OP_ARG
);
1606 if (G_UNLIKELY (cfg
->verbose_level
> 1)) {
1607 printf ("vret_addr = ");
1608 mono_print_ins (cfg
->vret_addr
);
1613 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1614 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1618 * take the arguments and generate the arch-specific
1619 * instructions to properly call the function in call.
1620 * This includes pushing, moving arguments to the right register
1622 * Issue: who does the spilling if needed, and when?
1625 emit_sig_cookie (MonoCompile
*cfg
, MonoCallInst
*call
, CallInfo
*cinfo
)
1627 MonoMethodSignature
*tmp_sig
;
1630 if (MONO_IS_TAILCALL_OPCODE (call
))
1633 /* FIXME: Add support for signature tokens to AOT */
1634 cfg
->disable_aot
= TRUE
;
1637 * mono_ArgIterator_Setup assumes the signature cookie is
1638 * passed first and all the arguments which were before it are
1639 * passed on the stack after the signature. So compensate by
1640 * passing a different signature.
1642 tmp_sig
= mono_metadata_signature_dup (call
->signature
);
1643 tmp_sig
->param_count
-= call
->signature
->sentinelpos
;
1644 tmp_sig
->sentinelpos
= 0;
1645 memcpy (tmp_sig
->params
, call
->signature
->params
+ call
->signature
->sentinelpos
, tmp_sig
->param_count
* sizeof (MonoType
*));
1647 MONO_INST_NEW (cfg
, sig_arg
, OP_ICONST
);
1648 sig_arg
->dreg
= mono_alloc_ireg (cfg
);
1649 sig_arg
->inst_p0
= tmp_sig
;
1650 MONO_ADD_INS (cfg
->cbb
, sig_arg
);
1652 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_sp
, cinfo
->sig_cookie
.offset
, sig_arg
->dreg
);
1656 mono_arch_emit_call (MonoCompile
*cfg
, MonoCallInst
*call
)
1659 MonoMethodSignature
*sig
;
1664 sig
= call
->signature
;
1665 n
= sig
->param_count
+ sig
->hasthis
;
1667 cinfo
= get_call_info (cfg
->mempool
, sig
);
1668 if (cinfo
->struct_ret
)
1669 call
->used_iregs
|= 1 << cinfo
->struct_ret
;
1671 for (i
= 0; i
< n
; ++i
) {
1672 ArgInfo
*ainfo
= cinfo
->args
+ i
;
1675 if (i
>= sig
->hasthis
)
1676 t
= sig
->params
[i
- sig
->hasthis
];
1678 t
= mono_get_int_type ();
1679 t
= mini_get_underlying_type (t
);
1681 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1682 /* Emit the signature cookie just before the implicit arguments */
1683 emit_sig_cookie (cfg
, call
, cinfo
);
1686 if (is_virtual
&& i
== 0) {
1687 /* the argument will be attached to the call instrucion */
1688 in
= call
->args
[i
];
1689 call
->used_iregs
|= 1 << ainfo
->reg
;
1692 in
= call
->args
[i
];
1693 if (ainfo
->storage
== ArgInIReg
) {
1694 #if SIZEOF_REGISTER == 4
1695 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1696 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1697 ins
->dreg
= mono_alloc_ireg (cfg
);
1698 ins
->sreg1
= MONO_LVREG_LS (in
->dreg
);
1699 MONO_ADD_INS (cfg
->cbb
, ins
);
1700 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
+ ls_word_idx
, FALSE
);
1702 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1703 ins
->dreg
= mono_alloc_ireg (cfg
);
1704 ins
->sreg1
= MONO_LVREG_MS (in
->dreg
);
1705 MONO_ADD_INS (cfg
->cbb
, ins
);
1706 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
+ ms_word_idx
, FALSE
);
1709 if (!t
->byref
&& (t
->type
== MONO_TYPE_R4
)) {
1712 #if PROMOTE_R4_TO_R8
1713 /* ??? - convert to single first? */
1714 MONO_INST_NEW (cfg
, ins
, OP_MIPS_CVTSD
);
1715 ins
->dreg
= mono_alloc_freg (cfg
);
1716 ins
->sreg1
= in
->dreg
;
1717 MONO_ADD_INS (cfg
->cbb
, ins
);
1722 /* trying to load float value into int registers */
1723 MONO_INST_NEW (cfg
, ins
, OP_MIPS_MFC1S
);
1724 ins
->dreg
= mono_alloc_ireg (cfg
);
1726 MONO_ADD_INS (cfg
->cbb
, ins
);
1727 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1728 } else if (!t
->byref
&& (t
->type
== MONO_TYPE_R8
)) {
1729 /* trying to load float value into int registers */
1730 MONO_INST_NEW (cfg
, ins
, OP_MIPS_MFC1D
);
1731 ins
->dreg
= mono_alloc_ireg (cfg
);
1732 ins
->sreg1
= in
->dreg
;
1733 MONO_ADD_INS (cfg
->cbb
, ins
);
1734 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1736 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1737 ins
->dreg
= mono_alloc_ireg (cfg
);
1738 ins
->sreg1
= in
->dreg
;
1739 MONO_ADD_INS (cfg
->cbb
, ins
);
1740 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1742 } else if (ainfo
->storage
== ArgStructByAddr
) {
1743 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1744 ins
->opcode
= OP_OUTARG_VT
;
1745 ins
->sreg1
= in
->dreg
;
1746 ins
->klass
= in
->klass
;
1747 ins
->inst_p0
= call
;
1748 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1749 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1750 MONO_ADD_INS (cfg
->cbb
, ins
);
1751 } else if (ainfo
->storage
== ArgStructByVal
) {
1752 /* this is further handled in mono_arch_emit_outarg_vt () */
1753 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1754 ins
->opcode
= OP_OUTARG_VT
;
1755 ins
->sreg1
= in
->dreg
;
1756 ins
->klass
= in
->klass
;
1757 ins
->inst_p0
= call
;
1758 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1759 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1760 MONO_ADD_INS (cfg
->cbb
, ins
);
1761 } else if (ainfo
->storage
== ArgOnStack
) {
1762 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1763 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1764 } else if (!t
->byref
&& ((t
->type
== MONO_TYPE_R4
) || (t
->type
== MONO_TYPE_R8
))) {
1765 if (t
->type
== MONO_TYPE_R8
)
1766 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER8_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1768 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER4_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1770 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1772 } else if (ainfo
->storage
== ArgInFReg
) {
1773 if (t
->type
== MONO_TYPE_VALUETYPE
) {
1774 /* this is further handled in mono_arch_emit_outarg_vt () */
1775 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1776 ins
->opcode
= OP_OUTARG_VT
;
1777 ins
->sreg1
= in
->dreg
;
1778 ins
->klass
= in
->klass
;
1779 ins
->inst_p0
= call
;
1780 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1781 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1782 MONO_ADD_INS (cfg
->cbb
, ins
);
1784 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1786 int dreg
= mono_alloc_freg (cfg
);
1788 if (ainfo
->size
== 4) {
1789 MONO_EMIT_NEW_UNALU (cfg
, OP_MIPS_CVTSD
, dreg
, in
->dreg
);
1791 MONO_INST_NEW (cfg
, ins
, OP_FMOVE
);
1793 ins
->sreg1
= in
->dreg
;
1794 MONO_ADD_INS (cfg
->cbb
, ins
);
1797 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1798 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1801 g_assert_not_reached ();
1805 /* Handle the case where there are no implicit arguments */
1806 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (n
== sig
->sentinelpos
))
1807 emit_sig_cookie (cfg
, call
, cinfo
);
1809 if (cinfo
->struct_ret
) {
1812 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
1813 vtarg
->sreg1
= call
->vret_var
->dreg
;
1814 vtarg
->dreg
= mono_alloc_preg (cfg
);
1815 MONO_ADD_INS (cfg
->cbb
, vtarg
);
1817 mono_call_inst_add_outarg_reg (cfg
, call
, vtarg
->dreg
, cinfo
->struct_ret
, FALSE
);
1821 * Reverse the call->out_args list.
1824 MonoInst
*prev
= NULL
, *list
= call
->out_args
, *next
;
1831 call
->out_args
= prev
;
1834 call
->stack_usage
= cinfo
->stack_usage
;
1835 cfg
->param_area
= MAX (cfg
->param_area
, cinfo
->stack_usage
);
1836 #if _MIPS_SIM == _ABIO32
1837 /* a0-a3 always present */
1838 cfg
->param_area
= MAX (cfg
->param_area
, 4 * SIZEOF_REGISTER
);
1840 cfg
->param_area
= (cfg
->param_area
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1841 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
1843 * should set more info in call, such as the stack space
1844 * used by the args that needs to be added back to esp
1849 mono_arch_emit_outarg_vt (MonoCompile
*cfg
, MonoInst
*ins
, MonoInst
*src
)
1851 MonoCallInst
*call
= (MonoCallInst
*)ins
->inst_p0
;
1852 ArgInfo
*ainfo
= ins
->inst_p1
;
1853 int ovf_size
= ainfo
->vtsize
;
1854 int doffset
= ainfo
->offset
;
1855 int i
, soffset
, dreg
;
1857 if (ainfo
->storage
== ArgStructByVal
) {
1859 if (cfg
->verbose_level
> 0) {
1860 char* nm
= mono_method_full_name (cfg
->method
, TRUE
);
1861 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1862 nm
, doffset
, ainfo
->size
, ovf_size
);
1868 for (i
= 0; i
< ainfo
->size
; ++i
) {
1869 dreg
= mono_alloc_ireg (cfg
);
1870 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, dreg
, src
->dreg
, soffset
);
1871 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
+ i
, FALSE
);
1872 soffset
+= SIZEOF_REGISTER
;
1874 if (ovf_size
!= 0) {
1875 mini_emit_memcpy (cfg
, mips_sp
, doffset
, src
->dreg
, soffset
, ovf_size
* sizeof (target_mgreg_t
), TARGET_SIZEOF_VOID_P
);
1877 } else if (ainfo
->storage
== ArgInFReg
) {
1878 int tmpr
= mono_alloc_freg (cfg
);
1880 if (ainfo
->size
== 4)
1881 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR4_MEMBASE
, tmpr
, src
->dreg
, 0);
1883 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR8_MEMBASE
, tmpr
, src
->dreg
, 0);
1884 dreg
= mono_alloc_freg (cfg
);
1885 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, dreg
, tmpr
);
1886 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1888 MonoInst
*vtcopy
= mono_compile_create_var (cfg
, m_class_get_byval_arg (src
->klass
), OP_LOCAL
);
1892 /* FIXME: alignment? */
1893 if (call
->signature
->pinvoke
) {
1894 size
= mono_type_native_stack_size (m_class_get_byval_arg (src
->klass
), NULL
);
1895 vtcopy
->backend
.is_pinvoke
= 1;
1897 size
= mini_type_stack_size (m_class_get_byval_arg (src
->klass
), NULL
);
1900 g_assert (ovf_size
> 0);
1902 EMIT_NEW_VARLOADA (cfg
, load
, vtcopy
, vtcopy
->inst_vtype
);
1903 mini_emit_memcpy (cfg
, load
->dreg
, 0, src
->dreg
, 0, size
, TARGET_SIZEOF_VOID_P
);
1906 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_at
, ainfo
->offset
, load
->dreg
);
1908 mono_call_inst_add_outarg_reg (cfg
, call
, load
->dreg
, ainfo
->reg
, FALSE
);
1913 mono_arch_emit_setret (MonoCompile
*cfg
, MonoMethod
*method
, MonoInst
*val
)
1915 MonoType
*ret
= mini_get_underlying_type (mono_method_signature_internal (method
)->ret
);
1918 #if (SIZEOF_REGISTER == 4)
1919 if (ret
->type
== MONO_TYPE_I8
|| ret
->type
== MONO_TYPE_U8
) {
1922 MONO_INST_NEW (cfg
, ins
, OP_SETLRET
);
1923 ins
->sreg1
= MONO_LVREG_LS (val
->dreg
);
1924 ins
->sreg2
= MONO_LVREG_MS (val
->dreg
);
1925 MONO_ADD_INS (cfg
->cbb
, ins
);
1929 if (ret
->type
== MONO_TYPE_R8
) {
1930 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, cfg
->ret
->dreg
, val
->dreg
);
1933 if (ret
->type
== MONO_TYPE_R4
) {
1934 MONO_EMIT_NEW_UNALU (cfg
, OP_MIPS_CVTSD
, cfg
->ret
->dreg
, val
->dreg
);
1938 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, cfg
->ret
->dreg
, val
->dreg
);
1942 mono_arch_peephole_pass_1 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1944 MonoInst
*ins
, *n
, *last_ins
= NULL
;
1946 if (cfg
->verbose_level
> 2)
1947 g_print ("Basic block %d peephole pass 1\n", bb
->block_num
);
1950 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
1951 if (cfg
->verbose_level
> 2)
1952 mono_print_ins_index (0, ins
);
1954 switch (ins
->opcode
) {
1956 case OP_LOAD_MEMBASE
:
1957 case OP_LOADI4_MEMBASE
:
1959 * OP_IADD reg2, reg1, const1
1960 * OP_LOAD_MEMBASE const2(reg2), reg3
1962 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1964 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
)){
1965 int const1
= last_ins
->inst_imm
;
1966 int const2
= ins
->inst_offset
;
1968 if (mips_is_imm16 (const1
+ const2
)) {
1969 ins
->inst_basereg
= last_ins
->sreg1
;
1970 ins
->inst_offset
= const1
+ const2
;
1980 bb
->last_ins
= last_ins
;
1984 mono_arch_peephole_pass_2 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1986 MonoInst
*ins
, *n
, *last_ins
= NULL
;
1989 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
1990 MonoInst
*last_ins
= ins
->prev
;
1992 switch (ins
->opcode
) {
1994 /* remove unnecessary multiplication with 1 */
1995 if (ins
->inst_imm
== 1) {
1996 if (ins
->dreg
!= ins
->sreg1
) {
1997 ins
->opcode
= OP_MOVE
;
1999 MONO_DELETE_INS (bb
, ins
);
2003 int power2
= mono_is_power_of_two (ins
->inst_imm
);
2005 ins
->opcode
= OP_SHL_IMM
;
2006 ins
->inst_imm
= power2
;
2010 case OP_LOAD_MEMBASE
:
2011 case OP_LOADI4_MEMBASE
:
2013 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2014 * OP_LOAD_MEMBASE offset(basereg), reg
2016 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_REG
2017 || last_ins
->opcode
== OP_STORE_MEMBASE_REG
) &&
2018 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2019 ins
->inst_offset
== last_ins
->inst_offset
) {
2020 if (ins
->dreg
== last_ins
->sreg1
) {
2021 MONO_DELETE_INS (bb
, ins
);
2024 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2025 ins
->opcode
= OP_MOVE
;
2026 ins
->sreg1
= last_ins
->sreg1
;
2031 * Note: reg1 must be different from the basereg in the second load
2032 * OP_LOAD_MEMBASE offset(basereg), reg1
2033 * OP_LOAD_MEMBASE offset(basereg), reg2
2035 * OP_LOAD_MEMBASE offset(basereg), reg1
2036 * OP_MOVE reg1, reg2
2038 if (last_ins
&& (last_ins
->opcode
== OP_LOADI4_MEMBASE
2039 || last_ins
->opcode
== OP_LOAD_MEMBASE
) &&
2040 ins
->inst_basereg
!= last_ins
->dreg
&&
2041 ins
->inst_basereg
== last_ins
->inst_basereg
&&
2042 ins
->inst_offset
== last_ins
->inst_offset
) {
2044 if (ins
->dreg
== last_ins
->dreg
) {
2045 MONO_DELETE_INS (bb
, ins
);
2048 ins
->opcode
= OP_MOVE
;
2049 ins
->sreg1
= last_ins
->dreg
;
2052 //g_assert_not_reached ();
2057 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2058 * OP_LOAD_MEMBASE offset(basereg), reg
2060 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2061 * OP_ICONST reg, imm
2063 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_IMM
2064 || last_ins
->opcode
== OP_STORE_MEMBASE_IMM
) &&
2065 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2066 ins
->inst_offset
== last_ins
->inst_offset
) {
2067 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2068 ins
->opcode
= OP_ICONST
;
2069 ins
->inst_c0
= last_ins
->inst_imm
;
2070 g_assert_not_reached (); // check this rule
2075 case OP_LOADU1_MEMBASE
:
2076 case OP_LOADI1_MEMBASE
:
2077 if (last_ins
&& (last_ins
->opcode
== OP_STOREI1_MEMBASE_REG
) &&
2078 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2079 ins
->inst_offset
== last_ins
->inst_offset
) {
2080 ins
->opcode
= (ins
->opcode
== OP_LOADI1_MEMBASE
) ? OP_ICONV_TO_I1
: OP_ICONV_TO_U1
;
2081 ins
->sreg1
= last_ins
->sreg1
;
2084 case OP_LOADU2_MEMBASE
:
2085 case OP_LOADI2_MEMBASE
:
2086 if (last_ins
&& (last_ins
->opcode
== OP_STOREI2_MEMBASE_REG
) &&
2087 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2088 ins
->inst_offset
== last_ins
->inst_offset
) {
2089 ins
->opcode
= (ins
->opcode
== OP_LOADI2_MEMBASE
) ? OP_ICONV_TO_I2
: OP_ICONV_TO_U2
;
2090 ins
->sreg1
= last_ins
->sreg1
;
2093 case OP_ICONV_TO_I4
:
2094 case OP_ICONV_TO_U4
:
2096 ins
->opcode
= OP_MOVE
;
2100 if (ins
->dreg
== ins
->sreg1
) {
2101 MONO_DELETE_INS (bb
, ins
);
2105 * OP_MOVE sreg, dreg
2106 * OP_MOVE dreg, sreg
2108 if (last_ins
&& last_ins
->opcode
== OP_MOVE
&&
2109 ins
->sreg1
== last_ins
->dreg
&&
2110 ins
->dreg
== last_ins
->sreg1
) {
2111 MONO_DELETE_INS (bb
, ins
);
2119 bb
->last_ins
= last_ins
;
2123 mono_arch_decompose_long_opts (MonoCompile
*cfg
, MonoInst
*ins
)
2131 switch (ins
->opcode
) {
2133 tmp1
= mono_alloc_ireg (cfg
);
2134 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2135 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
2136 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2137 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2142 tmp1
= mono_alloc_ireg (cfg
);
2143 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, ins
->dreg
+1, ins
->sreg1
+1, ins_get_l_low (ins
));
2144 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
2145 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, ins
->dreg
+2, ins
->sreg1
+2, ins_get_l_high (ins
));
2146 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2151 tmp1
= mono_alloc_ireg (cfg
);
2152 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2153 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
2154 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2155 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2160 tmp1
= mono_alloc_ireg (cfg
);
2161 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, ins
->dreg
+1, ins
->sreg1
+1, ins_get_l_low (ins
));
2162 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
2163 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, ins
->dreg
+2, ins
->sreg1
+2, ins_get_l_high (ins
));
2164 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2169 tmp1
= mono_alloc_ireg (cfg
);
2170 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, mips_zero
, ins
->sreg1
+1);
2171 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, mips_zero
, ins
->dreg
+1);
2172 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, mips_zero
, ins
->sreg1
+2);
2173 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2178 tmp1
= mono_alloc_ireg (cfg
);
2179 tmp2
= mono_alloc_ireg (cfg
);
2180 tmp3
= mono_alloc_ireg (cfg
);
2181 tmp4
= mono_alloc_ireg (cfg
);
2182 tmp5
= mono_alloc_ireg (cfg
);
2184 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2186 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2187 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp5
, ins
->dreg
+1, ins
->sreg1
+1);
2189 /* add the high 32-bits, and add in the carry from the low 32-bits */
2190 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2191 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, tmp5
, ins
->dreg
+2);
2193 /* Overflow happens if
2194 * neg + neg = pos or
2196 * XOR of the high bits returns 0 if the signs match
2197 * XOR of that with the high bit of the result return 1 if overflow.
2200 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2201 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
+2, ins
->sreg2
+2);
2203 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2204 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->dreg
+2, ins
->sreg2
+2);
2205 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tmp2
, tmp2
);
2207 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2208 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tmp3
, tmp2
, tmp1
);
2209 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp4
, tmp3
, 31);
2211 /* Now, if (tmp4 == 0) then overflow */
2212 MONO_EMIT_NEW_COMPARE_EXC (cfg
, EQ
, tmp4
, mips_zero
, "OverflowException");
2216 case OP_LADD_OVF_UN
:
2217 tmp1
= mono_alloc_ireg (cfg
);
2218 tmp2
= mono_alloc_ireg (cfg
);
2220 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2221 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
2222 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2223 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, tmp1
, ins
->dreg
+2);
2224 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp2
, ins
->dreg
+2, ins
->sreg1
+2);
2225 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp2
, mips_zero
, "OverflowException");
2230 tmp1
= mono_alloc_ireg (cfg
);
2231 tmp2
= mono_alloc_ireg (cfg
);
2232 tmp3
= mono_alloc_ireg (cfg
);
2233 tmp4
= mono_alloc_ireg (cfg
);
2234 tmp5
= mono_alloc_ireg (cfg
);
2236 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2238 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp5
, ins
->sreg1
+1, ins
->dreg
+1);
2239 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2240 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp5
);
2242 /* Overflow happens if
2243 * neg - pos = pos or
2245 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2247 * tmp1 = (lhs ^ rhs)
2248 * tmp2 = (lhs ^ result)
2249 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2252 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
+2, ins
->sreg2
+2);
2253 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->sreg1
+2, ins
->dreg
+2);
2254 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tmp3
, tmp2
, tmp1
);
2255 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp4
, tmp3
, 31);
2257 /* Now, if (tmp4 == 1) then overflow */
2258 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp4
, mips_zero
, "OverflowException");
2262 case OP_LSUB_OVF_UN
:
2263 tmp1
= mono_alloc_ireg (cfg
);
2264 tmp2
= mono_alloc_ireg (cfg
);
2266 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2267 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
2268 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2269 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2271 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp2
, ins
->sreg1
+2, ins
->dreg
+2);
2272 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp2
, mips_zero
, "OverflowException");
2275 case OP_LCONV_TO_OVF_I4_2
:
2276 tmp1
= mono_alloc_ireg (cfg
);
2278 /* Overflows if reg2 != sign extension of reg1 */
2279 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp1
, ins
->sreg1
, 31);
2280 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, ins
->sreg2
, tmp1
, "OverflowException");
2281 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
2290 mono_arch_decompose_opts (MonoCompile
*cfg
, MonoInst
*ins
)
2298 switch (ins
->opcode
) {
2300 tmp1
= mono_alloc_ireg (cfg
);
2301 tmp2
= mono_alloc_ireg (cfg
);
2302 tmp3
= mono_alloc_ireg (cfg
);
2303 tmp4
= mono_alloc_ireg (cfg
);
2304 tmp5
= mono_alloc_ireg (cfg
);
2306 /* add the operands */
2308 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2310 /* Overflow happens if
2311 * neg + neg = pos or
2314 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2315 * XOR of the high bit returns 0 if the signs match
2316 * XOR of that with the high bit of the result return 1 if overflow.
2319 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2320 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
, ins
->sreg2
);
2322 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2323 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->dreg
, ins
->sreg2
);
2324 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tmp3
, tmp2
);
2326 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2327 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tmp4
, tmp3
, tmp1
);
2329 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp5
, tmp4
, 31);
2331 /* Now, if (tmp5 == 0) then overflow */
2332 MONO_EMIT_NEW_COMPARE_EXC (cfg
, EQ
, tmp5
, mips_zero
, "OverflowException");
2333 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2334 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->dreg
);
2338 case OP_IADD_OVF_UN
:
2339 tmp1
= mono_alloc_ireg (cfg
);
2341 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2342 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
, ins
->sreg1
);
2343 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp1
, mips_zero
, "OverflowException");
2344 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2345 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->dreg
);
2350 tmp1
= mono_alloc_ireg (cfg
);
2351 tmp2
= mono_alloc_ireg (cfg
);
2352 tmp3
= mono_alloc_ireg (cfg
);
2353 tmp4
= mono_alloc_ireg (cfg
);
2354 tmp5
= mono_alloc_ireg (cfg
);
2356 /* add the operands */
2358 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2360 /* Overflow happens if
2361 * neg - pos = pos or
2363 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2365 * tmp1 = (lhs ^ rhs)
2366 * tmp2 = (lhs ^ result)
2367 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2370 /* tmp3 = 1 if the signs of the two inputs differ */
2371 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
, ins
->sreg2
);
2372 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->sreg1
, ins
->dreg
);
2373 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_MIPS_SLTI
, tmp3
, tmp1
, 0);
2374 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_MIPS_SLTI
, tmp4
, tmp2
, 0);
2375 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tmp5
, tmp4
, tmp3
);
2377 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp5
, mips_zero
, "OverflowException");
2378 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2379 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->dreg
);
2383 case OP_ISUB_OVF_UN
:
2384 tmp1
= mono_alloc_ireg (cfg
);
2386 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2387 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
, ins
->dreg
);
2388 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp1
, mips_zero
, "OverflowException");
2389 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2390 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->dreg
);
2397 map_to_reg_reg_op (int op
)
2406 case OP_COMPARE_IMM
:
2408 case OP_ICOMPARE_IMM
:
2410 case OP_LCOMPARE_IMM
:
2426 case OP_LOAD_MEMBASE
:
2427 return OP_LOAD_MEMINDEX
;
2428 case OP_LOADI4_MEMBASE
:
2429 return OP_LOADI4_MEMINDEX
;
2430 case OP_LOADU4_MEMBASE
:
2431 return OP_LOADU4_MEMINDEX
;
2432 case OP_LOADU1_MEMBASE
:
2433 return OP_LOADU1_MEMINDEX
;
2434 case OP_LOADI2_MEMBASE
:
2435 return OP_LOADI2_MEMINDEX
;
2436 case OP_LOADU2_MEMBASE
:
2437 return OP_LOADU2_MEMINDEX
;
2438 case OP_LOADI1_MEMBASE
:
2439 return OP_LOADI1_MEMINDEX
;
2440 case OP_LOADR4_MEMBASE
:
2441 return OP_LOADR4_MEMINDEX
;
2442 case OP_LOADR8_MEMBASE
:
2443 return OP_LOADR8_MEMINDEX
;
2444 case OP_STOREI1_MEMBASE_REG
:
2445 return OP_STOREI1_MEMINDEX
;
2446 case OP_STOREI2_MEMBASE_REG
:
2447 return OP_STOREI2_MEMINDEX
;
2448 case OP_STOREI4_MEMBASE_REG
:
2449 return OP_STOREI4_MEMINDEX
;
2450 case OP_STORE_MEMBASE_REG
:
2451 return OP_STORE_MEMINDEX
;
2452 case OP_STORER4_MEMBASE_REG
:
2453 return OP_STORER4_MEMINDEX
;
2454 case OP_STORER8_MEMBASE_REG
:
2455 return OP_STORER8_MEMINDEX
;
2456 case OP_STORE_MEMBASE_IMM
:
2457 return OP_STORE_MEMBASE_REG
;
2458 case OP_STOREI1_MEMBASE_IMM
:
2459 return OP_STOREI1_MEMBASE_REG
;
2460 case OP_STOREI2_MEMBASE_IMM
:
2461 return OP_STOREI2_MEMBASE_REG
;
2462 case OP_STOREI4_MEMBASE_IMM
:
2463 return OP_STOREI4_MEMBASE_REG
;
2464 case OP_STOREI8_MEMBASE_IMM
:
2465 return OP_STOREI8_MEMBASE_REG
;
2467 if (mono_op_imm_to_op (op
) == -1)
2468 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op
));
2469 return mono_op_imm_to_op (op
);
2473 map_to_mips_op (int op
)
2477 return OP_MIPS_FBEQ
;
2479 return OP_MIPS_FBGE
;
2481 return OP_MIPS_FBGT
;
2483 return OP_MIPS_FBLE
;
2485 return OP_MIPS_FBLT
;
2487 return OP_MIPS_FBNE
;
2489 return OP_MIPS_FBGE_UN
;
2491 return OP_MIPS_FBGT_UN
;
2493 return OP_MIPS_FBLE_UN
;
2495 return OP_MIPS_FBLT_UN
;
2503 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op
), __FUNCTION__
);
2504 g_assert_not_reached ();
2508 #define NEW_INS(cfg,after,dest,op) do { \
2509 MONO_INST_NEW((cfg), (dest), (op)); \
2510 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2513 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2515 MONO_INST_NEW(cfg, temp, (op)); \
2516 mono_bblock_insert_after_ins (bb, (pos), temp); \
2517 temp->dreg = (_dreg); \
2518 temp->sreg1 = (_sreg1); \
2519 temp->sreg2 = (_sreg2); \
2523 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2525 MONO_INST_NEW(cfg, temp, (op)); \
2526 mono_bblock_insert_after_ins (bb, (pos), temp); \
2527 temp->dreg = (_dreg); \
2528 temp->sreg1 = (_sreg1); \
2529 temp->inst_c0 = (_imm); \
2534 * Remove from the instruction list the instructions that can't be
2535 * represented with very simple instructions with no register
2539 mono_arch_lowering_pass (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2541 MonoInst
*ins
, *next
, *temp
, *last_ins
= NULL
;
2545 if (cfg
->verbose_level
> 2) {
2548 g_print ("BASIC BLOCK %d (before lowering)\n", bb
->block_num
);
2549 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2550 mono_print_ins_index (idx
++, ins
);
2556 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2558 switch (ins
->opcode
) {
2563 /* Branch opts can eliminate the branch */
2564 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2570 case OP_COMPARE_IMM
:
2571 case OP_ICOMPARE_IMM
:
2572 case OP_LCOMPARE_IMM
:
2574 /* Branch opts can eliminate the branch */
2575 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2579 if (ins
->inst_imm
) {
2580 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2581 temp
->inst_c0
= ins
->inst_imm
;
2582 temp
->dreg
= mono_alloc_ireg (cfg
);
2583 ins
->sreg2
= temp
->dreg
;
2587 ins
->sreg2
= mips_zero
;
2589 if (ins
->opcode
== OP_COMPARE_IMM
)
2590 ins
->opcode
= OP_COMPARE
;
2591 else if (ins
->opcode
== OP_ICOMPARE_IMM
)
2592 ins
->opcode
= OP_ICOMPARE
;
2593 else if (ins
->opcode
== OP_LCOMPARE_IMM
)
2594 ins
->opcode
= OP_LCOMPARE
;
2597 case OP_IDIV_UN_IMM
:
2600 case OP_IREM_UN_IMM
:
2601 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2602 temp
->inst_c0
= ins
->inst_imm
;
2603 temp
->dreg
= mono_alloc_ireg (cfg
);
2604 ins
->sreg2
= temp
->dreg
;
2605 if (ins
->opcode
== OP_IDIV_IMM
)
2606 ins
->opcode
= OP_IDIV
;
2607 else if (ins
->opcode
== OP_IREM_IMM
)
2608 ins
->opcode
= OP_IREM
;
2609 else if (ins
->opcode
== OP_IDIV_UN_IMM
)
2610 ins
->opcode
= OP_IDIV_UN
;
2611 else if (ins
->opcode
== OP_IREM_UN_IMM
)
2612 ins
->opcode
= OP_IREM_UN
;
2614 /* handle rem separately */
2621 if ((ins
->inst_imm
& 0xffff0000) && (ins
->inst_imm
& 0xffff)) {
2622 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2623 temp
->inst_c0
= ins
->inst_imm
;
2624 temp
->dreg
= mono_alloc_ireg (cfg
);
2625 ins
->sreg2
= temp
->dreg
;
2626 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2636 /* unsigned 16 bit immediate */
2637 if (ins
->inst_imm
& 0xffff0000) {
2638 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2639 temp
->inst_c0
= ins
->inst_imm
;
2640 temp
->dreg
= mono_alloc_ireg (cfg
);
2641 ins
->sreg2
= temp
->dreg
;
2642 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2649 /* signed 16 bit immediate */
2650 if (!mips_is_imm16 (ins
->inst_imm
)) {
2651 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2652 temp
->inst_c0
= ins
->inst_imm
;
2653 temp
->dreg
= mono_alloc_ireg (cfg
);
2654 ins
->sreg2
= temp
->dreg
;
2655 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2661 if (!mips_is_imm16 (-ins
->inst_imm
)) {
2662 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2663 temp
->inst_c0
= ins
->inst_imm
;
2664 temp
->dreg
= mono_alloc_ireg (cfg
);
2665 ins
->sreg2
= temp
->dreg
;
2666 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2672 if (ins
->inst_imm
== 1) {
2673 ins
->opcode
= OP_MOVE
;
2676 if (ins
->inst_imm
== 0) {
2677 ins
->opcode
= OP_ICONST
;
2681 imm
= mono_is_power_of_two (ins
->inst_imm
);
2683 ins
->opcode
= OP_SHL_IMM
;
2684 ins
->inst_imm
= imm
;
2687 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2688 temp
->inst_c0
= ins
->inst_imm
;
2689 temp
->dreg
= mono_alloc_ireg (cfg
);
2690 ins
->sreg2
= temp
->dreg
;
2691 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2694 case OP_LOCALLOC_IMM
:
2695 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2696 temp
->inst_c0
= ins
->inst_imm
;
2697 temp
->dreg
= mono_alloc_ireg (cfg
);
2698 ins
->sreg1
= temp
->dreg
;
2699 ins
->opcode
= OP_LOCALLOC
;
2702 case OP_LOADR4_MEMBASE
:
2703 case OP_STORER4_MEMBASE_REG
:
2704 /* we can do two things: load the immed in a register
2705 * and use an indexed load, or see if the immed can be
2706 * represented as an ad_imm + a load with a smaller offset
2707 * that fits. We just do the first for now, optimize later.
2709 if (mips_is_imm16 (ins
->inst_offset
))
2711 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2712 temp
->inst_c0
= ins
->inst_offset
;
2713 temp
->dreg
= mono_alloc_ireg (cfg
);
2714 ins
->sreg2
= temp
->dreg
;
2715 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2718 case OP_STORE_MEMBASE_IMM
:
2719 case OP_STOREI1_MEMBASE_IMM
:
2720 case OP_STOREI2_MEMBASE_IMM
:
2721 case OP_STOREI4_MEMBASE_IMM
:
2722 case OP_STOREI8_MEMBASE_IMM
:
2723 if (!ins
->inst_imm
) {
2724 ins
->sreg1
= mips_zero
;
2725 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2728 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2729 temp
->inst_c0
= ins
->inst_imm
;
2730 temp
->dreg
= mono_alloc_ireg (cfg
);
2731 ins
->sreg1
= temp
->dreg
;
2732 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2734 goto loop_start
; /* make it handle the possibly big ins->inst_offset */
2740 /* Branch opts can eliminate the branch */
2741 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2748 * remap compare/branch and compare/set
2749 * to MIPS specific opcodes.
2751 next
->opcode
= map_to_mips_op (next
->opcode
);
2752 next
->sreg1
= ins
->sreg1
;
2753 next
->sreg2
= ins
->sreg2
;
2760 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2761 temp
->inst_c0
= (guint32
)ins
->inst_p0
;
2762 temp
->dreg
= mono_alloc_ireg (cfg
);
2763 ins
->inst_basereg
= temp
->dreg
;
2764 ins
->inst_offset
= 0;
2765 ins
->opcode
= ins
->opcode
== OP_R4CONST
? OP_LOADR4_MEMBASE
: OP_LOADR8_MEMBASE
;
2767 /* make it handle the possibly big ins->inst_offset
2768 * later optimize to use lis + load_membase
2773 g_assert (ins_is_compare(last_ins
));
2774 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->sreg1
, last_ins
->sreg2
);
2775 NULLIFY_INS(last_ins
);
2779 g_assert (ins_is_compare(last_ins
));
2780 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->sreg1
, last_ins
->sreg2
);
2781 NULLIFY_INS(last_ins
);
2785 g_assert (ins_is_compare(last_ins
));
2786 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2787 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2788 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2792 g_assert (ins_is_compare(last_ins
));
2793 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2794 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2795 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2799 g_assert (ins_is_compare(last_ins
));
2800 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2801 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2802 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2806 g_assert (ins_is_compare(last_ins
));
2807 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2808 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2809 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2813 g_assert (ins_is_compare(last_ins
));
2814 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2815 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2816 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2820 g_assert (ins_is_compare(last_ins
));
2821 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2822 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2823 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2827 g_assert (ins_is_compare(last_ins
));
2828 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2829 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2830 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2834 g_assert (ins_is_compare(last_ins
));
2835 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2836 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2837 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2842 g_assert (ins_is_compare(last_ins
));
2843 last_ins
->opcode
= OP_IXOR
;
2844 last_ins
->dreg
= mono_alloc_ireg(cfg
);
2845 INS_REWRITE_IMM(ins
, OP_MIPS_SLTIU
, last_ins
->dreg
, 1);
2850 INS_REWRITE(ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2851 NULLIFY_INS(last_ins
);
2857 INS_REWRITE(ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2858 NULLIFY_INS(last_ins
);
2863 g_assert (ins_is_compare(last_ins
));
2864 INS_REWRITE(ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2865 MONO_DELETE_INS(bb
, last_ins
);
2870 g_assert (ins_is_compare(last_ins
));
2871 INS_REWRITE(ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2872 MONO_DELETE_INS(bb
, last_ins
);
2875 case OP_COND_EXC_EQ
:
2876 case OP_COND_EXC_IEQ
:
2877 g_assert (ins_is_compare(last_ins
));
2878 INS_REWRITE(ins
, OP_MIPS_COND_EXC_EQ
, last_ins
->sreg1
, last_ins
->sreg2
);
2879 MONO_DELETE_INS(bb
, last_ins
);
2882 case OP_COND_EXC_GE
:
2883 case OP_COND_EXC_IGE
:
2884 g_assert (ins_is_compare(last_ins
));
2885 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GE
, last_ins
->sreg1
, last_ins
->sreg2
);
2886 MONO_DELETE_INS(bb
, last_ins
);
2889 case OP_COND_EXC_GT
:
2890 case OP_COND_EXC_IGT
:
2891 g_assert (ins_is_compare(last_ins
));
2892 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GT
, last_ins
->sreg1
, last_ins
->sreg2
);
2893 MONO_DELETE_INS(bb
, last_ins
);
2896 case OP_COND_EXC_LE
:
2897 case OP_COND_EXC_ILE
:
2898 g_assert (ins_is_compare(last_ins
));
2899 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LE
, last_ins
->sreg1
, last_ins
->sreg2
);
2900 MONO_DELETE_INS(bb
, last_ins
);
2903 case OP_COND_EXC_LT
:
2904 case OP_COND_EXC_ILT
:
2905 g_assert (ins_is_compare(last_ins
));
2906 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LT
, last_ins
->sreg1
, last_ins
->sreg2
);
2907 MONO_DELETE_INS(bb
, last_ins
);
2910 case OP_COND_EXC_NE_UN
:
2911 case OP_COND_EXC_INE_UN
:
2912 g_assert (ins_is_compare(last_ins
));
2913 INS_REWRITE(ins
, OP_MIPS_COND_EXC_NE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2914 MONO_DELETE_INS(bb
, last_ins
);
2917 case OP_COND_EXC_GE_UN
:
2918 case OP_COND_EXC_IGE_UN
:
2919 g_assert (ins_is_compare(last_ins
));
2920 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2921 MONO_DELETE_INS(bb
, last_ins
);
2924 case OP_COND_EXC_GT_UN
:
2925 case OP_COND_EXC_IGT_UN
:
2926 g_assert (ins_is_compare(last_ins
));
2927 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GT_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2928 MONO_DELETE_INS(bb
, last_ins
);
2931 case OP_COND_EXC_LE_UN
:
2932 case OP_COND_EXC_ILE_UN
:
2933 g_assert (ins_is_compare(last_ins
));
2934 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2935 MONO_DELETE_INS(bb
, last_ins
);
2938 case OP_COND_EXC_LT_UN
:
2939 case OP_COND_EXC_ILT_UN
:
2940 g_assert (ins_is_compare(last_ins
));
2941 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LT_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2942 MONO_DELETE_INS(bb
, last_ins
);
2945 case OP_COND_EXC_OV
:
2946 case OP_COND_EXC_IOV
: {
2947 int tmp1
, tmp2
, tmp3
, tmp4
, tmp5
;
2948 MonoInst
*pos
= last_ins
;
2950 /* Overflow happens if
2951 * neg + neg = pos or
2954 * (bit31s of operands match) AND (bit31 of operand
2955 * != bit31 of result)
2956 * XOR of the high bit returns 0 if the signs match
2957 * XOR of that with the high bit of the result return 1
2960 g_assert (last_ins
->opcode
== OP_IADC
);
2962 tmp1
= mono_alloc_ireg (cfg
);
2963 tmp2
= mono_alloc_ireg (cfg
);
2964 tmp3
= mono_alloc_ireg (cfg
);
2965 tmp4
= mono_alloc_ireg (cfg
);
2966 tmp5
= mono_alloc_ireg (cfg
);
2968 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2969 INS (pos
, OP_IXOR
, tmp1
, last_ins
->sreg1
, last_ins
->sreg2
);
2971 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2972 INS (pos
, OP_IXOR
, tmp2
, last_ins
->dreg
, last_ins
->sreg2
);
2973 INS (pos
, OP_INOT
, tmp3
, tmp2
, -1);
2975 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2976 INS (pos
, OP_IOR
, tmp4
, tmp3
, tmp1
);
2977 INS_IMM (pos
, OP_SHR_IMM
, tmp5
, tmp4
, 31);
2979 /* Now, if (tmp5 == 0) then overflow */
2980 INS_REWRITE(ins
, OP_MIPS_COND_EXC_EQ
, tmp5
, mips_zero
);
2985 case OP_COND_EXC_NO
:
2986 case OP_COND_EXC_INO
:
2987 g_assert_not_reached ();
2991 case OP_COND_EXC_IC
:
2992 g_assert_not_reached ();
2995 case OP_COND_EXC_NC
:
2996 case OP_COND_EXC_INC
:
2997 g_assert_not_reached ();
3003 bb
->last_ins
= last_ins
;
3004 bb
->max_vreg
= cfg
->next_vreg
;
3007 if (cfg
->verbose_level
> 2) {
3010 g_print ("BASIC BLOCK %d (after lowering)\n", bb
->block_num
);
3011 MONO_BB_FOR_EACH_INS (bb
, ins
) {
3012 mono_print_ins_index (idx
++, ins
);
3021 emit_float_to_int (MonoCompile
*cfg
, guchar
*code
, int dreg
, int sreg
, int size
, gboolean is_signed
)
3023 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3025 mips_truncwd (code
, mips_ftemp
, sreg
);
3027 mips_cvtwd (code
, mips_ftemp
, sreg
);
3029 mips_mfc1 (code
, dreg
, mips_ftemp
);
3032 mips_andi (code
, dreg
, dreg
, 0xff);
3033 else if (size
== 2) {
3034 mips_sll (code
, dreg
, dreg
, 16);
3035 mips_srl (code
, dreg
, dreg
, 16);
3039 mips_sll (code
, dreg
, dreg
, 24);
3040 mips_sra (code
, dreg
, dreg
, 24);
3042 else if (size
== 2) {
3043 mips_sll (code
, dreg
, dreg
, 16);
3044 mips_sra (code
, dreg
, dreg
, 16);
3051 * emit_load_volatile_arguments:
3053 * Load volatile arguments from the stack to the original input registers.
3054 * Required before a tailcall.
3057 emit_load_volatile_arguments(MonoCompile
*cfg
, guint8
*code
)
3059 MonoMethod
*method
= cfg
->method
;
3060 MonoMethodSignature
*sig
;
3065 sig
= mono_method_signature_internal (method
);
3067 if (!cfg
->arch
.cinfo
)
3068 cfg
->arch
.cinfo
= get_call_info (cfg
->mempool
, sig
);
3069 cinfo
= cfg
->arch
.cinfo
;
3071 if (cinfo
->struct_ret
) {
3072 ArgInfo
*ainfo
= &cinfo
->ret
;
3073 inst
= cfg
->vret_addr
;
3074 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3077 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
3078 ArgInfo
*ainfo
= cinfo
->args
+ i
;
3079 inst
= cfg
->args
[i
];
3080 if (inst
->opcode
== OP_REGVAR
) {
3081 if (ainfo
->storage
== ArgInIReg
)
3082 MIPS_MOVE (code
, ainfo
->reg
, inst
->dreg
);
3083 else if (ainfo
->storage
== ArgInFReg
)
3084 g_assert_not_reached();
3085 else if (ainfo
->storage
== ArgOnStack
) {
3088 g_assert_not_reached ();
3090 if (ainfo
->storage
== ArgInIReg
) {
3091 g_assert (mips_is_imm16 (inst
->inst_offset
));
3092 switch (ainfo
->size
) {
3094 mips_lb (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3097 mips_lh (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3101 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3104 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+ ls_word_offset
);
3105 mips_lw (code
, ainfo
->reg
+ 1, inst
->inst_basereg
, inst
->inst_offset
+ ms_word_offset
);
3108 g_assert_not_reached ();
3111 } else if (ainfo
->storage
== ArgOnStack
) {
3113 } else if (ainfo
->storage
== ArgInFReg
) {
3114 g_assert (mips_is_imm16 (inst
->inst_offset
));
3115 if (ainfo
->size
== 8) {
3116 #if _MIPS_SIM == _ABIO32
3117 mips_lwc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+ ls_word_offset
);
3118 mips_lwc1 (code
, ainfo
->reg
+1, inst
->inst_basereg
, inst
->inst_offset
+ ms_word_offset
);
3119 #elif _MIPS_SIM == _ABIN32
3120 mips_ldc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3123 else if (ainfo
->size
== 4)
3124 mips_lwc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3126 g_assert_not_reached ();
3127 } else if (ainfo
->storage
== ArgStructByVal
) {
3129 int doffset
= inst
->inst_offset
;
3131 g_assert (mips_is_imm16 (inst
->inst_offset
));
3132 g_assert (mips_is_imm16 (inst
->inst_offset
+ ainfo
->size
* sizeof (target_mgreg_t
)));
3133 for (i
= 0; i
< ainfo
->size
; ++i
) {
3134 mips_lw (code
, ainfo
->reg
+ i
, inst
->inst_basereg
, doffset
);
3135 doffset
+= SIZEOF_REGISTER
;
3137 } else if (ainfo
->storage
== ArgStructByAddr
) {
3138 g_assert (mips_is_imm16 (inst
->inst_offset
));
3139 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3141 g_assert_not_reached ();
3149 emit_reserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3151 int size
= cfg
->param_area
;
3153 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3154 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3159 ppc_lwz (code
, ppc_r0
, 0, ppc_sp
);
3160 if (ppc_is_imm16 (-size
)) {
3161 ppc_stwu (code
, ppc_r0
, -size
, ppc_sp
);
3163 ppc_load (code
, ppc_r12
, -size
);
3164 ppc_stwux (code
, ppc_r0
, ppc_sp
, ppc_r12
);
3171 emit_unreserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3173 int size
= cfg
->param_area
;
3175 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3176 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3181 ppc_lwz (code
, ppc_r0
, 0, ppc_sp
);
3182 if (ppc_is_imm16 (size
)) {
3183 ppc_stwu (code
, ppc_r0
, size
, ppc_sp
);
3185 ppc_load (code
, ppc_r12
, size
);
3186 ppc_stwux (code
, ppc_r0
, ppc_sp
, ppc_r12
);
3193 mono_arch_output_basic_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
3197 guint8
*code
= cfg
->native_code
+ cfg
->code_len
;
3198 MonoInst
*last_ins
= NULL
;
3202 /* we don't align basic blocks of loops on mips */
3204 if (cfg
->verbose_level
> 2)
3205 g_print ("Basic block %d starting at offset 0x%x\n", bb
->block_num
, bb
->native_offset
);
3207 cpos
= bb
->max_offset
;
3209 MONO_BB_FOR_EACH_INS (bb
, ins
) {
3210 const guint offset
= code
- cfg
->native_code
;
3211 set_code_cursor (cfg
, code
);
3212 max_len
= ins_get_size (ins
->opcode
);
3213 code
= realloc_code (cfg
, max_len
);
3215 mono_debug_record_line_number (cfg
, ins
, offset
);
3216 if (cfg
->verbose_level
> 2) {
3217 g_print (" @ 0x%x\t", offset
);
3218 mono_print_ins_index (ins_cnt
++, ins
);
3220 /* Check for virtual regs that snuck by */
3221 g_assert ((ins
->dreg
>= -1) && (ins
->dreg
< 32));
3223 switch (ins
->opcode
) {
3224 case OP_RELAXED_NOP
:
3227 case OP_DUMMY_ICONST
:
3228 case OP_DUMMY_I8CONST
:
3229 case OP_DUMMY_R8CONST
:
3230 case OP_DUMMY_R4CONST
:
3231 case OP_NOT_REACHED
:
3234 case OP_IL_SEQ_POINT
:
3235 mono_add_seq_point (cfg
, bb
, ins
, code
- cfg
->native_code
);
3237 case OP_SEQ_POINT
: {
3238 if (ins
->flags
& MONO_INST_SINGLE_STEP_LOC
) {
3239 guint32 addr
= (guint32
)ss_trigger_page
;
3241 mips_load_const (code
, mips_t9
, addr
);
3242 mips_lw (code
, mips_t9
, mips_t9
, 0);
3245 mono_add_seq_point (cfg
, bb
, ins
, code
- cfg
->native_code
);
3248 * A placeholder for a possible breakpoint inserted by
3249 * mono_arch_set_breakpoint ().
3251 /* mips_load_const () + mips_lw */
3258 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3259 mips_mflo (code
, ins
->dreg
);
3260 mips_mfhi (code
, ins
->dreg
+1);
3263 mips_multu (code
, ins
->sreg1
, ins
->sreg2
);
3264 mips_mflo (code
, ins
->dreg
);
3265 mips_mfhi (code
, ins
->dreg
+1);
3267 case OP_MEMORY_BARRIER
:
3268 mips_sync (code
, 0);
3270 case OP_STOREI1_MEMBASE_IMM
:
3271 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3272 if (mips_is_imm16 (ins
->inst_offset
)) {
3273 mips_sb (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3275 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3276 mips_sb (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3279 case OP_STOREI2_MEMBASE_IMM
:
3280 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3281 if (mips_is_imm16 (ins
->inst_offset
)) {
3282 mips_sh (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3284 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3285 mips_sh (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3288 case OP_STOREI8_MEMBASE_IMM
:
3289 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3290 if (mips_is_imm16 (ins
->inst_offset
)) {
3291 mips_sd (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3293 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3294 mips_sd (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3297 case OP_STORE_MEMBASE_IMM
:
3298 case OP_STOREI4_MEMBASE_IMM
:
3299 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3300 if (mips_is_imm16 (ins
->inst_offset
)) {
3301 mips_sw (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3303 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3304 mips_sw (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3307 case OP_STOREI1_MEMBASE_REG
:
3308 if (mips_is_imm16 (ins
->inst_offset
)) {
3309 mips_sb (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3311 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3312 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3313 mips_sb (code
, ins
->sreg1
, mips_at
, 0);
3316 case OP_STOREI2_MEMBASE_REG
:
3317 if (mips_is_imm16 (ins
->inst_offset
)) {
3318 mips_sh (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3320 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3321 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3322 mips_sh (code
, ins
->sreg1
, mips_at
, 0);
3325 case OP_STORE_MEMBASE_REG
:
3326 case OP_STOREI4_MEMBASE_REG
:
3327 if (mips_is_imm16 (ins
->inst_offset
)) {
3328 mips_sw (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3330 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3331 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3332 mips_sw (code
, ins
->sreg1
, mips_at
, 0);
3335 case OP_STOREI8_MEMBASE_REG
:
3336 if (mips_is_imm16 (ins
->inst_offset
)) {
3337 mips_sd (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3339 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3340 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3341 mips_sd (code
, ins
->sreg1
, mips_at
, 0);
3345 g_assert_not_reached ();
3346 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3347 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3349 case OP_LOADI8_MEMBASE
:
3350 if (mips_is_imm16 (ins
->inst_offset
)) {
3351 mips_ld (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3353 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3354 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3355 mips_ld (code
, ins
->dreg
, mips_at
, 0);
3358 case OP_LOAD_MEMBASE
:
3359 case OP_LOADI4_MEMBASE
:
3360 case OP_LOADU4_MEMBASE
:
3361 g_assert (ins
->dreg
!= -1);
3362 if (mips_is_imm16 (ins
->inst_offset
)) {
3363 mips_lw (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3365 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3366 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3367 mips_lw (code
, ins
->dreg
, mips_at
, 0);
3370 case OP_LOADI1_MEMBASE
:
3371 if (mips_is_imm16 (ins
->inst_offset
)) {
3372 mips_lb (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3374 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3375 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3376 mips_lb (code
, ins
->dreg
, mips_at
, 0);
3379 case OP_LOADU1_MEMBASE
:
3380 if (mips_is_imm16 (ins
->inst_offset
)) {
3381 mips_lbu (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3383 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3384 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3385 mips_lbu (code
, ins
->dreg
, mips_at
, 0);
3388 case OP_LOADI2_MEMBASE
:
3389 if (mips_is_imm16 (ins
->inst_offset
)) {
3390 mips_lh (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3392 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3393 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3394 mips_lh (code
, ins
->dreg
, mips_at
, 0);
3397 case OP_LOADU2_MEMBASE
:
3398 if (mips_is_imm16 (ins
->inst_offset
)) {
3399 mips_lhu (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3401 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3402 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3403 mips_lhu (code
, ins
->dreg
, mips_at
, 0);
3406 case OP_ICONV_TO_I1
:
3407 mips_sll (code
, mips_at
, ins
->sreg1
, 24);
3408 mips_sra (code
, ins
->dreg
, mips_at
, 24);
3410 case OP_ICONV_TO_I2
:
3411 mips_sll (code
, mips_at
, ins
->sreg1
, 16);
3412 mips_sra (code
, ins
->dreg
, mips_at
, 16);
3414 case OP_ICONV_TO_U1
:
3415 mips_andi (code
, ins
->dreg
, ins
->sreg1
, 0xff);
3417 case OP_ICONV_TO_U2
:
3418 mips_sll (code
, mips_at
, ins
->sreg1
, 16);
3419 mips_srl (code
, ins
->dreg
, mips_at
, 16);
3422 mips_slt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3425 g_assert (mips_is_imm16 (ins
->inst_imm
));
3426 mips_slti (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3429 mips_sltu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3432 g_assert (mips_is_imm16 (ins
->inst_imm
));
3433 mips_sltiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3437 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3438 * So instead of emitting a trap, we emit a call a C function and place a
3441 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_JIT_ICALL_ID
, GUINT_TO_POINTER (MONO_JIT_ICALL_mono_break
));
3442 mips_load (code
, mips_t9
, 0x1f1f1f1f);
3443 mips_jalr (code
, mips_t9
, mips_ra
);
3447 mips_addu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3450 mips_daddu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3455 g_assert (mips_is_imm16 (ins
->inst_imm
));
3456 mips_addiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3459 g_assert (mips_is_imm16 (ins
->inst_imm
));
3460 mips_daddiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3464 mips_subu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3467 mips_dsubu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3472 // we add the negated value
3473 g_assert (mips_is_imm16 (-ins
->inst_imm
));
3474 mips_addiu (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
3478 // we add the negated value
3479 g_assert (mips_is_imm16 (-ins
->inst_imm
));
3480 mips_daddiu (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
3485 mips_and (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3491 g_assert (!(ins
->inst_imm
& 0xffff0000));
3492 mips_andi (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3497 guint32
*divisor_is_m1
;
3498 guint32
*dividend_is_minvalue
;
3499 guint32
*divisor_is_zero
;
3501 mips_load_const (code
, mips_at
, -1);
3502 divisor_is_m1
= (guint32
*)(void *)code
;
3503 mips_bne (code
, ins
->sreg2
, mips_at
, 0);
3504 mips_lui (code
, mips_at
, mips_zero
, 0x8000);
3505 dividend_is_minvalue
= (guint32
*)(void *)code
;
3506 mips_bne (code
, ins
->sreg1
, mips_at
, 0);
3509 /* Divide Int32.MinValue by -1 -- throw exception */
3510 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3512 mips_patch (divisor_is_m1
, (guint32
)code
);
3513 mips_patch (dividend_is_minvalue
, (guint32
)code
);
3515 /* Put divide in branch delay slot (NOT YET) */
3516 divisor_is_zero
= (guint32
*)(void *)code
;
3517 mips_bne (code
, ins
->sreg2
, mips_zero
, 0);
3520 /* Divide by zero -- throw exception */
3521 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3523 mips_patch (divisor_is_zero
, (guint32
)code
);
3524 mips_div (code
, ins
->sreg1
, ins
->sreg2
);
3525 if (ins
->opcode
== OP_IDIV
)
3526 mips_mflo (code
, ins
->dreg
);
3528 mips_mfhi (code
, ins
->dreg
);
3533 guint32
*divisor_is_zero
= (guint32
*)(void *)code
;
3535 /* Put divide in branch delay slot (NOT YET) */
3536 mips_bne (code
, ins
->sreg2
, mips_zero
, 0);
3539 /* Divide by zero -- throw exception */
3540 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3542 mips_patch (divisor_is_zero
, (guint32
)code
);
3543 mips_divu (code
, ins
->sreg1
, ins
->sreg2
);
3544 if (ins
->opcode
== OP_IDIV_UN
)
3545 mips_mflo (code
, ins
->dreg
);
3547 mips_mfhi (code
, ins
->dreg
);
3551 g_assert_not_reached ();
3553 ppc_load (code
, ppc_r12
, ins
->inst_imm
);
3554 ppc_divwod (code
, ins
->dreg
, ins
->sreg1
, ppc_r12
);
3555 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3556 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3557 /* FIXME: use OverflowException for 0x80000000/-1 */
3558 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
3560 g_assert_not_reached();
3563 g_assert_not_reached ();
3565 mips_or (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3569 g_assert (!(ins
->inst_imm
& 0xffff0000));
3570 mips_ori (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3573 mips_xor (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3577 /* unsigned 16-bit immediate */
3578 g_assert (!(ins
->inst_imm
& 0xffff0000));
3579 mips_xori (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3582 mips_sllv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3586 mips_sll (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3589 mips_srav (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3592 mips_dsrav (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3596 mips_sra (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3599 mips_dsra (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x3f);
3602 case OP_ISHR_UN_IMM
:
3603 mips_srl (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3605 case OP_LSHR_UN_IMM
:
3606 mips_dsrl (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x3f);
3609 mips_srlv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3612 mips_dsrlv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3616 mips_nor (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3619 mips_subu (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3622 mips_dsubu (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3626 mips_mul (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3628 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3629 mips_mflo (code
, ins
->dreg
);
3634 #if SIZEOF_REGISTER == 8
3636 mips_dmult (code
, ins
->sreg1
, ins
->sreg2
);
3637 mips_mflo (code
, ins
->dreg
);
3642 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3643 mips_mflo (code
, ins
->dreg
);
3644 mips_mfhi (code
, mips_at
);
3647 mips_sra (code
, mips_temp
, ins
->dreg
, 31);
3648 patch
= (guint32
*)(void *)code
;
3649 mips_beq (code
, mips_temp
, mips_at
, 0);
3651 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3652 mips_patch (patch
, (guint32
)code
);
3655 case OP_IMUL_OVF_UN
: {
3657 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3658 mips_mflo (code
, ins
->dreg
);
3659 mips_mfhi (code
, mips_at
);
3662 patch
= (guint32
*)(void *)code
;
3663 mips_beq (code
, mips_at
, mips_zero
, 0);
3665 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3666 mips_patch (patch
, (guint32
)code
);
3670 mips_load_const (code
, ins
->dreg
, ins
->inst_c0
);
3672 #if SIZEOF_REGISTER == 8
3674 mips_load_const (code
, ins
->dreg
, ins
->inst_c0
);
3678 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_i1
, ins
->inst_p0
);
3679 mips_load (code
, ins
->dreg
, 0);
3683 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3685 case OP_MIPS_MTC1S_2
:
3686 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3687 mips_mtc1 (code
, ins
->dreg
+1, ins
->sreg2
);
3690 mips_mfc1 (code
, ins
->dreg
, ins
->sreg1
);
3693 mips_dmtc1 (code
, ins
->dreg
, ins
->sreg1
);
3697 mips_dmfc1 (code
, ins
->dreg
, ins
->sreg1
);
3699 mips_mfc1 (code
, ins
->dreg
, ins
->sreg1
+ ls_word_idx
);
3700 mips_mfc1 (code
, ins
->dreg
+1, ins
->sreg1
+ ms_word_idx
);
3704 case OP_ICONV_TO_I4
:
3705 case OP_ICONV_TO_U4
:
3707 if (ins
->dreg
!= ins
->sreg1
)
3708 MIPS_MOVE (code
, ins
->dreg
, ins
->sreg1
);
3710 #if SIZEOF_REGISTER == 8
3712 mips_dsll (code
, ins
->dreg
, ins
->sreg1
, 32);
3713 mips_dsrl (code
, ins
->dreg
, ins
->dreg
, 32);
3716 mips_dsll (code
, ins
->dreg
, ins
->sreg1
, 32);
3717 mips_dsra (code
, ins
->dreg
, ins
->dreg
, 32);
3721 int lsreg
= mips_v0
+ ls_word_idx
;
3722 int msreg
= mips_v0
+ ms_word_idx
;
3724 /* Get sreg1 into lsreg, sreg2 into msreg */
3726 if (ins
->sreg1
== msreg
) {
3727 if (ins
->sreg1
!= mips_at
)
3728 MIPS_MOVE (code
, mips_at
, ins
->sreg1
);
3729 if (ins
->sreg2
!= msreg
)
3730 MIPS_MOVE (code
, msreg
, ins
->sreg2
);
3731 MIPS_MOVE (code
, lsreg
, mips_at
);
3734 if (ins
->sreg2
!= msreg
)
3735 MIPS_MOVE (code
, msreg
, ins
->sreg2
);
3736 if (ins
->sreg1
!= lsreg
)
3737 MIPS_MOVE (code
, lsreg
, ins
->sreg1
);
3742 if (ins
->dreg
!= ins
->sreg1
) {
3743 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
3746 case OP_MOVE_F_TO_I4
:
3747 mips_cvtsd (code
, mips_ftemp
, ins
->sreg1
);
3748 mips_mfc1 (code
, ins
->dreg
, mips_ftemp
);
3750 case OP_MOVE_I4_TO_F
:
3751 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3752 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
3755 /* Convert from double to float and leave it there */
3756 mips_cvtsd (code
, ins
->dreg
, ins
->sreg1
);
3758 case OP_FCONV_TO_R4
:
3760 mips_cvtsd (code
, ins
->dreg
, ins
->sreg1
);
3762 /* Just a move, no precision change */
3763 if (ins
->dreg
!= ins
->sreg1
) {
3764 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
3769 /* ensure ins->sreg1 is not NULL */
3770 mips_lw (code
, mips_zero
, ins
->sreg1
, 0);
3773 g_assert (mips_is_imm16 (cfg
->sig_cookie
));
3774 mips_lw (code
, mips_at
, cfg
->frame_reg
, cfg
->sig_cookie
);
3775 mips_sw (code
, mips_at
, ins
->sreg1
, 0);
3788 case OP_VOIDCALL_REG
:
3790 case OP_FCALL_MEMBASE
:
3791 case OP_LCALL_MEMBASE
:
3792 case OP_VCALL_MEMBASE
:
3793 case OP_VCALL2_MEMBASE
:
3794 case OP_VOIDCALL_MEMBASE
:
3795 case OP_CALL_MEMBASE
:
3796 call
= (MonoCallInst
*)ins
;
3797 switch (ins
->opcode
) {
3804 mono_call_add_patch_info (cfg
, call
, offset
);
3805 if (ins
->flags
& MONO_INST_HAS_METHOD
) {
3806 mips_load (code
, mips_t9
, call
->method
);
3809 mips_load (code
, mips_t9
, call
->fptr
);
3811 mips_jalr (code
, mips_t9
, mips_ra
);
3818 case OP_VOIDCALL_REG
:
3820 MIPS_MOVE (code
, mips_t9
, ins
->sreg1
);
3821 mips_jalr (code
, mips_t9
, mips_ra
);
3824 case OP_FCALL_MEMBASE
:
3825 case OP_LCALL_MEMBASE
:
3826 case OP_VCALL_MEMBASE
:
3827 case OP_VCALL2_MEMBASE
:
3828 case OP_VOIDCALL_MEMBASE
:
3829 case OP_CALL_MEMBASE
:
3830 mips_lw (code
, mips_t9
, ins
->sreg1
, ins
->inst_offset
);
3831 mips_jalr (code
, mips_t9
, mips_ra
);
3835 #if PROMOTE_R4_TO_R8
3836 /* returned an FP R4 (single), promote to R8 (double) in place */
3837 switch (ins
->opcode
) {
3840 case OP_FCALL_MEMBASE
:
3841 if (call
->signature
->ret
->type
== MONO_TYPE_R4
)
3842 mips_cvtds (code
, mips_f0
, mips_f0
);
3850 int area_offset
= cfg
->param_area
;
3852 /* Round up ins->sreg1, mips_at ends up holding size */
3853 mips_addiu (code
, mips_at
, ins
->sreg1
, 31);
3854 mips_addiu (code
, mips_temp
, mips_zero
, ~31);
3855 mips_and (code
, mips_at
, mips_at
, mips_temp
);
3857 mips_subu (code
, mips_sp
, mips_sp
, mips_at
);
3858 g_assert (mips_is_imm16 (area_offset
));
3859 mips_addiu (code
, ins
->dreg
, mips_sp
, area_offset
);
3861 if (ins
->flags
& MONO_INST_INIT
) {
3864 buf
= (guint32
*)(void*)code
;
3865 mips_beq (code
, mips_at
, mips_zero
, 0);
3868 mips_move (code
, mips_temp
, ins
->dreg
);
3869 mips_sb (code
, mips_zero
, mips_temp
, 0);
3870 mips_addiu (code
, mips_at
, mips_at
, -1);
3871 mips_bne (code
, mips_at
, mips_zero
, -3);
3872 mips_addiu (code
, mips_temp
, mips_temp
, 1);
3874 mips_patch (buf
, (guint32
)code
);
3879 gpointer addr
= mono_arch_get_throw_exception(NULL
, FALSE
);
3880 mips_move (code
, mips_a0
, ins
->sreg1
);
3881 mips_call (code
, mips_t9
, addr
);
3882 mips_break (code
, 0xfc);
3886 gpointer addr
= mono_arch_get_rethrow_exception(NULL
, FALSE
);
3887 mips_move (code
, mips_a0
, ins
->sreg1
);
3888 mips_call (code
, mips_t9
, addr
);
3889 mips_break (code
, 0xfb);
3892 case OP_START_HANDLER
: {
3894 * The START_HANDLER instruction marks the beginning of
3895 * a handler block. It is called using a call
3896 * instruction, so mips_ra contains the return address.
3897 * Since the handler executes in the same stack frame
3898 * as the method itself, we can't use save/restore to
3899 * save the return address. Instead, we save it into
3900 * a dedicated variable.
3902 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3903 g_assert (spvar
->inst_basereg
!= mips_sp
);
3904 code
= emit_reserve_param_area (cfg
, code
);
3906 if (mips_is_imm16 (spvar
->inst_offset
)) {
3907 mips_sw (code
, mips_ra
, spvar
->inst_basereg
, spvar
->inst_offset
);
3909 mips_load_const (code
, mips_at
, spvar
->inst_offset
);
3910 mips_addu (code
, mips_at
, mips_at
, spvar
->inst_basereg
);
3911 mips_sw (code
, mips_ra
, mips_at
, 0);
3915 case OP_ENDFILTER
: {
3916 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3917 g_assert (spvar
->inst_basereg
!= mips_sp
);
3918 code
= emit_unreserve_param_area (cfg
, code
);
3920 if (ins
->sreg1
!= mips_v0
)
3921 MIPS_MOVE (code
, mips_v0
, ins
->sreg1
);
3922 if (mips_is_imm16 (spvar
->inst_offset
)) {
3923 mips_lw (code
, mips_ra
, spvar
->inst_basereg
, spvar
->inst_offset
);
3925 mips_load_const (code
, mips_at
, spvar
->inst_offset
);
3926 mips_addu (code
, mips_at
, mips_at
, spvar
->inst_basereg
);
3927 mips_lw (code
, mips_ra
, mips_at
, 0);
3929 mips_jr (code
, mips_ra
);
3933 case OP_ENDFINALLY
: {
3934 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3935 g_assert (spvar
->inst_basereg
!= mips_sp
);
3936 code
= emit_unreserve_param_area (cfg
, code
);
3937 mips_lw (code
, mips_t9
, spvar
->inst_basereg
, spvar
->inst_offset
);
3938 mips_jalr (code
, mips_t9
, mips_ra
);
3942 case OP_CALL_HANDLER
:
3943 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
3944 mips_lui (code
, mips_t9
, mips_zero
, 0);
3945 mips_addiu (code
, mips_t9
, mips_t9
, 0);
3946 mips_jalr (code
, mips_t9
, mips_ra
);
3948 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3949 for (GList
*tmp
= ins
->inst_eh_blocks
; tmp
!= bb
->clause_holes
; tmp
= tmp
->prev
)
3950 mono_cfg_add_try_hole (cfg
, ((MonoLeaveClause
*) tmp
->data
)->clause
, code
, bb
);
3953 ins
->inst_c0
= code
- cfg
->native_code
;
3956 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
3957 if (cfg
->arch
.long_branch
) {
3958 mips_lui (code
, mips_at
, mips_zero
, 0);
3959 mips_addiu (code
, mips_at
, mips_at
, 0);
3960 mips_jr (code
, mips_at
);
3964 mips_beq (code
, mips_zero
, mips_zero
, 0);
3969 mips_jr (code
, ins
->sreg1
);
3975 max_len
+= 4 * GPOINTER_TO_INT (ins
->klass
);
3976 code
= realloc_code (cfg
, max_len
);
3978 g_assert (ins
->sreg1
!= -1);
3979 mips_sll (code
, mips_at
, ins
->sreg1
, 2);
3980 if (1 || !(cfg
->flags
& MONO_CFG_HAS_CALLS
))
3981 MIPS_MOVE (code
, mips_t8
, mips_ra
);
3982 mips_bgezal (code
, mips_zero
, 1); /* bal */
3984 mips_addu (code
, mips_t9
, mips_ra
, mips_at
);
3985 /* Table is 16 or 20 bytes from target of bal above */
3986 if (1 || !(cfg
->flags
& MONO_CFG_HAS_CALLS
)) {
3987 MIPS_MOVE (code
, mips_ra
, mips_t8
);
3988 mips_lw (code
, mips_t9
, mips_t9
, 20);
3991 mips_lw (code
, mips_t9
, mips_t9
, 16);
3992 mips_jalr (code
, mips_t9
, mips_t8
);
3994 for (i
= 0; i
< GPOINTER_TO_INT (ins
->klass
); ++i
)
3995 mips_emit32 (code
, 0xfefefefe);
4000 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4001 mips_beq (code
, mips_at
, mips_zero
, 2);
4003 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4009 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4010 mips_bltz (code
, mips_at
, 2);
4012 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4018 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4019 mips_bgtz (code
, mips_at
, 2);
4021 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4024 case OP_MIPS_COND_EXC_EQ
:
4025 case OP_MIPS_COND_EXC_GE
:
4026 case OP_MIPS_COND_EXC_GT
:
4027 case OP_MIPS_COND_EXC_LE
:
4028 case OP_MIPS_COND_EXC_LT
:
4029 case OP_MIPS_COND_EXC_NE_UN
:
4030 case OP_MIPS_COND_EXC_GE_UN
:
4031 case OP_MIPS_COND_EXC_GT_UN
:
4032 case OP_MIPS_COND_EXC_LE_UN
:
4033 case OP_MIPS_COND_EXC_LT_UN
:
4035 case OP_MIPS_COND_EXC_OV
:
4036 case OP_MIPS_COND_EXC_NO
:
4037 case OP_MIPS_COND_EXC_C
:
4038 case OP_MIPS_COND_EXC_NC
:
4040 case OP_MIPS_COND_EXC_IEQ
:
4041 case OP_MIPS_COND_EXC_IGE
:
4042 case OP_MIPS_COND_EXC_IGT
:
4043 case OP_MIPS_COND_EXC_ILE
:
4044 case OP_MIPS_COND_EXC_ILT
:
4045 case OP_MIPS_COND_EXC_INE_UN
:
4046 case OP_MIPS_COND_EXC_IGE_UN
:
4047 case OP_MIPS_COND_EXC_IGT_UN
:
4048 case OP_MIPS_COND_EXC_ILE_UN
:
4049 case OP_MIPS_COND_EXC_ILT_UN
:
4051 case OP_MIPS_COND_EXC_IOV
:
4052 case OP_MIPS_COND_EXC_INO
:
4053 case OP_MIPS_COND_EXC_IC
:
4054 case OP_MIPS_COND_EXC_INC
: {
4058 /* If the condition is true, raise the exception */
4060 /* need to reverse test to skip around exception raising */
4062 /* For the moment, branch around a branch to avoid reversing
4065 /* Remember, an unpatched branch to 0 branches to the delay slot */
4066 switch (ins
->opcode
) {
4067 case OP_MIPS_COND_EXC_EQ
:
4068 throw = (guint32
*)(void *)code
;
4069 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, 0);
4073 case OP_MIPS_COND_EXC_NE_UN
:
4074 throw = (guint32
*)(void *)code
;
4075 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, 0);
4079 case OP_MIPS_COND_EXC_LE_UN
:
4080 mips_sltu (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
4081 throw = (guint32
*)(void *)code
;
4082 mips_beq (code
, mips_at
, mips_zero
, 0);
4086 case OP_MIPS_COND_EXC_GT
:
4087 mips_slt (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
4088 throw = (guint32
*)(void *)code
;
4089 mips_bne (code
, mips_at
, mips_zero
, 0);
4093 case OP_MIPS_COND_EXC_GT_UN
:
4094 mips_sltu (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
4095 throw = (guint32
*)(void *)code
;
4096 mips_bne (code
, mips_at
, mips_zero
, 0);
4100 case OP_MIPS_COND_EXC_LT
:
4101 mips_slt (code
, mips_at
, ins
->sreg1
, ins
->sreg2
);
4102 throw = (guint32
*)(void *)code
;
4103 mips_bne (code
, mips_at
, mips_zero
, 0);
4107 case OP_MIPS_COND_EXC_LT_UN
:
4108 mips_sltu (code
, mips_at
, ins
->sreg1
, ins
->sreg2
);
4109 throw = (guint32
*)(void *)code
;
4110 mips_bne (code
, mips_at
, mips_zero
, 0);
4115 /* Not yet implemented */
4116 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins
->opcode
));
4117 g_assert_not_reached ();
4119 skip
= (guint32
*)(void *)code
;
4120 mips_beq (code
, mips_zero
, mips_zero
, 0);
4122 mips_patch (throw, (guint32
)code
);
4123 code
= mips_emit_exc_by_name (code
, ins
->inst_p1
);
4124 mips_patch (skip
, (guint32
)code
);
4125 cfg
->bb_exit
->max_offset
+= 24;
4134 code
= mips_emit_cond_branch (cfg
, code
, ins
->opcode
, ins
);
4137 /* floating point opcodes */
4140 if (((guint32
)ins
->inst_p0
) & (1 << 15))
4141 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16)+1);
4143 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16));
4144 mips_ldc1 (code
, ins
->dreg
, mips_at
, ((guint32
)ins
->inst_p0
) & 0xffff);
4146 mips_load_const (code
, mips_at
, ins
->inst_p0
);
4147 mips_lwc1 (code
, ins
->dreg
, mips_at
, ls_word_offset
);
4148 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, ms_word_offset
);
4152 if (((guint32
)ins
->inst_p0
) & (1 << 15))
4153 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16)+1);
4155 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16));
4156 mips_lwc1 (code
, ins
->dreg
, mips_at
, ((guint32
)ins
->inst_p0
) & 0xffff);
4157 #if PROMOTE_R4_TO_R8
4158 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4161 case OP_STORER8_MEMBASE_REG
:
4162 if (mips_is_imm16 (ins
->inst_offset
)) {
4163 #if _MIPS_SIM == _ABIO32
4164 mips_swc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
+ ls_word_offset
);
4165 mips_swc1 (code
, ins
->sreg1
+1, ins
->inst_destbasereg
, ins
->inst_offset
+ ms_word_offset
);
4166 #elif _MIPS_SIM == _ABIN32
4167 mips_sdc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
4170 mips_load_const (code
, mips_at
, ins
->inst_offset
);
4171 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
4172 mips_swc1 (code
, ins
->sreg1
, mips_at
, ls_word_offset
);
4173 mips_swc1 (code
, ins
->sreg1
+1, mips_at
, ms_word_offset
);
4176 case OP_LOADR8_MEMBASE
:
4177 if (mips_is_imm16 (ins
->inst_offset
)) {
4178 #if _MIPS_SIM == _ABIO32
4179 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
+ ls_word_offset
);
4180 mips_lwc1 (code
, ins
->dreg
+1, ins
->inst_basereg
, ins
->inst_offset
+ ms_word_offset
);
4181 #elif _MIPS_SIM == _ABIN32
4182 mips_ldc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4185 mips_load_const (code
, mips_at
, ins
->inst_offset
);
4186 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
4187 mips_lwc1 (code
, ins
->dreg
, mips_at
, ls_word_offset
);
4188 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, ms_word_offset
);
4191 case OP_STORER4_MEMBASE_REG
:
4192 g_assert (mips_is_imm16 (ins
->inst_offset
));
4193 #if PROMOTE_R4_TO_R8
4194 /* Need to convert ins->sreg1 to single-precision first */
4195 mips_cvtsd (code
, mips_ftemp
, ins
->sreg1
);
4196 mips_swc1 (code
, mips_ftemp
, ins
->inst_destbasereg
, ins
->inst_offset
);
4198 mips_swc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
4202 g_assert (mips_is_imm16 (ins
->inst_offset
));
4203 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4205 case OP_LOADR4_MEMBASE
:
4206 g_assert (mips_is_imm16 (ins
->inst_offset
));
4207 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4208 #if PROMOTE_R4_TO_R8
4209 /* Convert to double precision in place */
4210 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4213 case OP_LOADR4_MEMINDEX
:
4214 mips_addu (code
, mips_at
, ins
->inst_basereg
, ins
->sreg2
);
4215 mips_lwc1 (code
, ins
->dreg
, mips_at
, 0);
4217 case OP_LOADR8_MEMINDEX
:
4218 mips_addu (code
, mips_at
, ins
->inst_basereg
, ins
->sreg2
);
4219 #if _MIPS_SIM == _ABIO32
4220 mips_lwc1 (code
, ins
->dreg
, mips_at
, ls_word_offset
);
4221 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, ms_word_offset
);
4222 #elif _MIPS_SIM == _ABIN32
4223 mips_ldc1 (code
, ins
->dreg
, mips_at
, 0);
4226 case OP_STORER4_MEMINDEX
:
4227 mips_addu (code
, mips_at
, ins
->inst_destbasereg
, ins
->sreg2
);
4228 #if PROMOTE_R4_TO_R8
4229 /* Need to convert ins->sreg1 to single-precision first */
4230 mips_cvtsd (code
, mips_ftemp
, ins
->sreg1
);
4231 mips_swc1 (code
, mips_ftemp
, mips_at
, 0);
4233 mips_swc1 (code
, ins
->sreg1
, mips_at
, 0);
4236 case OP_STORER8_MEMINDEX
:
4237 mips_addu (code
, mips_at
, ins
->inst_destbasereg
, ins
->sreg2
);
4238 #if _MIPS_SIM == _ABIO32
4239 mips_swc1 (code
, ins
->sreg1
, mips_at
, ls_word_offset
);
4240 mips_swc1 (code
, ins
->sreg1
+1, mips_at
, ms_word_offset
);
4241 #elif _MIPS_SIM == _ABIN32
4242 mips_sdc1 (code
, ins
->sreg1
, mips_at
, 0);
4245 case OP_ICONV_TO_R_UN
: {
4246 static const guint64 adjust_val
= 0x41F0000000000000ULL
;
4248 /* convert unsigned int to double */
4249 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4250 mips_bgez (code
, ins
->sreg1
, 5);
4251 mips_cvtdw (code
, ins
->dreg
, mips_ftemp
);
4253 mips_load (code
, mips_at
, (guint32
) &adjust_val
);
4254 mips_ldc1 (code
, mips_ftemp
, mips_at
, 0);
4255 mips_faddd (code
, ins
->dreg
, ins
->dreg
, mips_ftemp
);
4256 /* target is here */
4259 case OP_ICONV_TO_R4
:
4260 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4261 mips_cvtsw (code
, ins
->dreg
, mips_ftemp
);
4262 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4264 case OP_ICONV_TO_R8
:
4265 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4266 mips_cvtdw (code
, ins
->dreg
, mips_ftemp
);
4268 case OP_FCONV_TO_I1
:
4269 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, TRUE
);
4271 case OP_FCONV_TO_U1
:
4272 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, FALSE
);
4274 case OP_FCONV_TO_I2
:
4275 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, TRUE
);
4277 case OP_FCONV_TO_U2
:
4278 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, FALSE
);
4280 case OP_FCONV_TO_I4
:
4282 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, TRUE
);
4284 case OP_FCONV_TO_U4
:
4286 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, FALSE
);
4289 mips_fsqrtd (code
, ins
->dreg
, ins
->sreg1
);
4292 mips_faddd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4295 mips_fsubd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4298 mips_fmuld (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4301 mips_fdivd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4304 mips_fnegd (code
, ins
->dreg
, ins
->sreg1
);
4307 mips_fcmpd (code
, MIPS_FPU_EQ
, ins
->sreg1
, ins
->sreg2
);
4308 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4309 mips_fbtrue (code
, 2);
4311 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4314 mips_fcmpd (code
, MIPS_FPU_LT
, ins
->sreg1
, ins
->sreg2
);
4315 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4316 mips_fbtrue (code
, 2);
4318 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4321 /* Less than, or Unordered */
4322 mips_fcmpd (code
, MIPS_FPU_ULT
, ins
->sreg1
, ins
->sreg2
);
4323 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4324 mips_fbtrue (code
, 2);
4326 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4329 mips_fcmpd (code
, MIPS_FPU_ULE
, ins
->sreg1
, ins
->sreg2
);
4330 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4331 mips_fbtrue (code
, 2);
4333 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4336 /* Greater than, or Unordered */
4337 mips_fcmpd (code
, MIPS_FPU_OLE
, ins
->sreg1
, ins
->sreg2
);
4338 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4339 mips_fbtrue (code
, 2);
4341 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4346 case OP_MIPS_FBLT_UN
:
4348 case OP_MIPS_FBGT_UN
:
4350 case OP_MIPS_FBGE_UN
:
4352 case OP_MIPS_FBLE_UN
: {
4354 gboolean is_true
= TRUE
, is_ordered
= FALSE
;
4355 guint32
*buf
= NULL
;
4357 switch (ins
->opcode
) {
4371 case OP_MIPS_FBLT_UN
:
4372 cond
= MIPS_FPU_ULT
;
4380 case OP_MIPS_FBGT_UN
:
4381 cond
= MIPS_FPU_OLE
;
4389 case OP_MIPS_FBGE_UN
:
4390 cond
= MIPS_FPU_OLT
;
4394 cond
= MIPS_FPU_OLE
;
4398 case OP_MIPS_FBLE_UN
:
4399 cond
= MIPS_FPU_ULE
;
4403 g_assert_not_reached ();
4407 /* Skip the check if unordered */
4408 mips_fcmpd (code
, MIPS_FPU_UN
, ins
->sreg1
, ins
->sreg2
);
4410 buf
= (guint32
*)code
;
4411 mips_fbtrue (code
, 0);
4415 mips_fcmpd (code
, cond
, ins
->sreg1
, ins
->sreg2
);
4417 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4419 mips_fbtrue (code
, 0);
4421 mips_fbfalse (code
, 0);
4425 mips_patch (buf
, (guint32
)code
);
4429 guint32
*branch_patch
;
4431 mips_mfc1 (code
, mips_at
, ins
->sreg1
+1);
4432 mips_srl (code
, mips_at
, mips_at
, 16+4);
4433 mips_andi (code
, mips_at
, mips_at
, 2047);
4434 mips_addiu (code
, mips_at
, mips_at
, -2047);
4436 branch_patch
= (guint32
*)(void *)code
;
4437 mips_bne (code
, mips_at
, mips_zero
, 0);
4440 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4441 mips_patch (branch_patch
, (guint32
)code
);
4442 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
4446 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_c1
, ins
->inst_p0
);
4447 mips_load (code
, ins
->dreg
, 0x0f0f0f0f);
4449 case OP_LIVERANGE_START
: {
4450 if (cfg
->verbose_level
> 1)
4451 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg
, ins
->inst_c0
)->vreg
, (int)(code
- cfg
->native_code
));
4452 MONO_VARINFO (cfg
, ins
->inst_c0
)->live_range_start
= code
- cfg
->native_code
;
4455 case OP_LIVERANGE_END
: {
4456 if (cfg
->verbose_level
> 1)
4457 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg
, ins
->inst_c0
)->vreg
, (int)(code
- cfg
->native_code
));
4458 MONO_VARINFO (cfg
, ins
->inst_c0
)->live_range_end
= code
- cfg
->native_code
;
4461 case OP_GC_SAFE_POINT
:
4466 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins
->opcode
), __FUNCTION__
);
4467 g_assert_not_reached ();
4470 if ((cfg
->opt
& MONO_OPT_BRANCH
) && ((code
- cfg
->native_code
- offset
) > max_len
)) {
4471 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4472 mono_inst_name (ins
->opcode
), max_len
, code
- cfg
->native_code
- offset
);
4473 g_assert_not_reached ();
4481 set_code_cursor (cfg
, code
);
4485 mono_arch_register_lowlevel_calls (void)
4490 mono_arch_patch_code (MonoCompile
*cfg
, MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*ji
, gboolean run_cctors
, MonoError
*error
)
4492 MonoJumpInfo
*patch_info
;
4496 for (patch_info
= ji
; patch_info
; patch_info
= patch_info
->next
) {
4497 unsigned char *ip
= patch_info
->ip
.i
+ code
;
4498 const unsigned char *target
= NULL
;
4500 switch (patch_info
->type
) {
4501 case MONO_PATCH_INFO_IP
:
4502 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)ip
);
4504 case MONO_PATCH_INFO_SWITCH
: {
4505 gpointer
*table
= (gpointer
*)patch_info
->data
.table
->table
;
4508 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)table
);
4510 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
4511 table
[i
] = (int)patch_info
->data
.table
->table
[i
] + code
;
4515 case MONO_PATCH_INFO_METHODCONST
:
4516 case MONO_PATCH_INFO_CLASS
:
4517 case MONO_PATCH_INFO_IMAGE
:
4518 case MONO_PATCH_INFO_FIELD
:
4519 case MONO_PATCH_INFO_VTABLE
:
4520 case MONO_PATCH_INFO_IID
:
4521 case MONO_PATCH_INFO_SFLDA
:
4522 case MONO_PATCH_INFO_LDSTR
:
4523 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
4524 case MONO_PATCH_INFO_LDTOKEN
:
4525 case MONO_PATCH_INFO_R4
:
4526 case MONO_PATCH_INFO_R8
:
4527 /* from OP_AOTCONST : lui + addiu */
4528 target
= mono_resolve_patch_target (method
, domain
, code
, patch_info
, run_cctors
, error
);
4529 return_if_nok (error
);
4531 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)target
);
4534 case MONO_PATCH_INFO_EXC_NAME
:
4535 g_assert_not_reached ();
4536 *((gconstpointer
*)(void *)(ip
+ 1)) = patch_info
->data
.name
;
4539 case MONO_PATCH_INFO_NONE
:
4540 /* everything is dealt with at epilog output time */
4543 target
= mono_resolve_patch_target (method
, domain
, code
, patch_info
, run_cctors
, error
);
4544 return_if_nok (error
);
4546 mips_patch ((guint32
*)(void *)ip
, (guint32
)target
);
4553 mips_adjust_stackframe(MonoCompile
*cfg
)
4556 int delta
, threshold
, i
;
4557 MonoMethodSignature
*sig
;
4560 if (cfg
->stack_offset
== cfg
->arch
.local_alloc_offset
)
4563 /* adjust cfg->stack_offset for account for down-spilling */
4564 cfg
->stack_offset
+= SIZEOF_REGISTER
;
4566 /* re-align cfg->stack_offset if needed (due to var spilling) */
4567 cfg
->stack_offset
= (cfg
->stack_offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
4568 delta
= cfg
->stack_offset
- cfg
->arch
.local_alloc_offset
;
4569 if (cfg
->verbose_level
> 2) {
4570 g_print ("mips_adjust_stackframe:\n");
4571 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg
->arch
.local_alloc_offset
, cfg
->stack_offset
);
4573 threshold
= cfg
->arch
.local_alloc_offset
;
4574 ra_offset
= cfg
->stack_offset
- sizeof(gpointer
);
4575 if (cfg
->verbose_level
> 2) {
4576 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset
, ra_offset
, delta
, delta
);
4579 sig
= mono_method_signature_internal (cfg
->method
);
4580 if (sig
&& sig
->ret
&& MONO_TYPE_ISSTRUCT (sig
->ret
)) {
4581 cfg
->vret_addr
->inst_offset
+= delta
;
4583 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4584 MonoInst
*inst
= cfg
->args
[i
];
4586 inst
->inst_offset
+= delta
;
4590 * loads and stores based off the frame reg that (used to) lie
4591 * above the spill var area need to be increased by 'delta'
4592 * to make room for the spill vars.
4594 /* Need to find loads and stores to adjust that
4595 * are above where the spillvars were inserted, but
4596 * which are not the spillvar references themselves.
4598 * Idea - since all offsets from fp are positive, make
4599 * spillvar offsets negative to begin with so we can spot
4604 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
4608 if (cfg
->verbose_level
> 2) {
4609 g_print ("BASIC BLOCK %d:\n", bb
->block_num
);
4611 MONO_BB_FOR_EACH_INS (bb
, ins
) {
4615 if (cfg
->verbose_level
> 2) {
4616 mono_print_ins_index (ins_cnt
, ins
);
4618 /* The == mips_sp tests catch FP spills */
4619 if (MONO_IS_LOAD_MEMBASE(ins
) && ((ins
->inst_basereg
== mips_fp
) ||
4620 (ins
->inst_basereg
== mips_sp
))) {
4621 switch (ins
->opcode
) {
4622 case OP_LOADI8_MEMBASE
:
4623 case OP_LOADR8_MEMBASE
:
4630 } else if (MONO_IS_STORE_MEMBASE(ins
) && ((ins
->dreg
== mips_fp
) ||
4631 (ins
->dreg
== mips_sp
))) {
4632 switch (ins
->opcode
) {
4633 case OP_STOREI8_MEMBASE_REG
:
4634 case OP_STORER8_MEMBASE_REG
:
4635 case OP_STOREI8_MEMBASE_IMM
:
4643 if (((ins
->opcode
== OP_ADD_IMM
) || (ins
->opcode
== OP_IADD_IMM
)) && (ins
->sreg1
== cfg
->frame_reg
))
4646 if (ins
->inst_c0
>= threshold
) {
4647 ins
->inst_c0
+= delta
;
4648 if (cfg
->verbose_level
> 2) {
4650 mono_print_ins_index (ins_cnt
, ins
);
4653 else if (ins
->inst_c0
< 0) {
4654 /* Adj_c0 holds the size of the datatype. */
4655 ins
->inst_c0
= - ins
->inst_c0
- adj_c0
;
4656 if (cfg
->verbose_level
> 2) {
4658 mono_print_ins_index (ins_cnt
, ins
);
4661 g_assert (ins
->inst_c0
!= ra_offset
);
4664 if (ins
->inst_imm
>= threshold
) {
4665 ins
->inst_imm
+= delta
;
4666 if (cfg
->verbose_level
> 2) {
4668 mono_print_ins_index (ins_cnt
, ins
);
4671 g_assert (ins
->inst_c0
!= ra_offset
);
4681 * Stack frame layout:
4683 * ------------------- sp + cfg->stack_usage + cfg->param_area
4684 * param area incoming
4685 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4687 * ------------------- sp + cfg->stack_usage
4689 * ------------------- sp + cfg->stack_usage-4
4691 * ------------------- sp +
4692 * MonoLMF structure optional
4693 * ------------------- sp + cfg->arch.lmf_offset
4694 * saved registers s0-s8
4695 * ------------------- sp + cfg->arch.iregs_offset
4697 * ------------------- sp + cfg->param_area
4698 * param area outgoing
4699 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4701 * ------------------- sp
4705 mono_arch_emit_prolog (MonoCompile
*cfg
)
4707 MonoMethod
*method
= cfg
->method
;
4708 MonoMethodSignature
*sig
;
4710 int alloc_size
, pos
, i
, max_offset
;
4711 int alloc2_size
= 0;
4714 guint32 iregs_to_save
= 0;
4716 guint32 fregs_to_save
= 0;
4718 /* lmf_offset is the offset of the LMF from our stack pointer. */
4719 guint32 lmf_offset
= cfg
->arch
.lmf_offset
;
4723 sig
= mono_method_signature_internal (method
);
4724 cfg
->code_size
= 768 + sig
->param_count
* 20;
4725 code
= cfg
->native_code
= g_malloc (cfg
->code_size
);
4728 * compute max_offset in order to use short forward jumps.
4731 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
4732 MonoInst
*ins
= bb
->code
;
4733 bb
->max_offset
= max_offset
;
4735 MONO_BB_FOR_EACH_INS (bb
, ins
)
4736 max_offset
+= ins_get_size (ins
->opcode
);
4738 if (max_offset
> 0xffff)
4739 cfg
->arch
.long_branch
= TRUE
;
4742 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4743 * This means that we have to adjust the offsets inside instructions which reference
4744 * arguments received on the stack, since the initial offset doesn't take into
4745 * account spill slots.
4747 mips_adjust_stackframe (cfg
);
4749 /* Offset between current sp and the CFA */
4751 mono_emit_unwind_op_def_cfa (cfg
, code
, mips_sp
, cfa_offset
);
4753 /* stack_offset should not be changed here. */
4754 alloc_size
= cfg
->stack_offset
;
4755 cfg
->stack_usage
= alloc_size
;
4757 iregs_to_save
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
4760 fregs_to_save
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
4762 fregs_to_save
= MONO_ARCH_CALLEE_SAVED_FREGS
;
4763 fregs_to_save
|= (fregs_to_save
<< 1);
4766 /* If the stack size is too big, save 1024 bytes to start with
4767 * so the prologue can use imm16(reg) addressing, then allocate
4768 * the rest of the frame.
4770 if (alloc_size
> ((1 << 15) - 1024)) {
4771 alloc2_size
= alloc_size
- 1024;
4775 g_assert (mips_is_imm16 (-alloc_size
));
4776 mips_addiu (code
, mips_sp
, mips_sp
, -alloc_size
);
4777 cfa_offset
= alloc_size
;
4778 mono_emit_unwind_op_def_cfa_offset (cfg
, code
, cfa_offset
);
4781 if ((cfg
->flags
& MONO_CFG_HAS_CALLS
) || ALWAYS_SAVE_RA
) {
4782 int offset
= alloc_size
+ MIPS_RET_ADDR_OFFSET
;
4783 if (mips_is_imm16(offset
))
4784 mips_sw (code
, mips_ra
, mips_sp
, offset
);
4786 g_assert_not_reached ();
4788 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4789 mono_emit_unwind_op_offset (cfg
, code
, mips_ra
, offset
- cfa_offset
);
4792 /* XXX - optimize this later to not save all regs if LMF constructed */
4793 pos
= cfg
->arch
.iregs_offset
- alloc2_size
;
4795 if (iregs_to_save
) {
4796 /* save used registers in own stack frame (at pos) */
4797 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
4798 if (iregs_to_save
& (1 << i
)) {
4799 g_assert (pos
< (int)(cfg
->stack_usage
- sizeof(gpointer
)));
4800 g_assert (mips_is_imm16(pos
));
4801 MIPS_SW (code
, i
, mips_sp
, pos
);
4802 mono_emit_unwind_op_offset (cfg
, code
, i
, pos
- cfa_offset
);
4803 pos
+= SIZEOF_REGISTER
;
4808 // FIXME: Don't save registers twice if there is an LMF
4809 // s8 has to be special cased since it is overwritten with the updated value
4811 if (method
->save_lmf
) {
4812 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
4813 int offset
= lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, iregs
[i
]);
4814 g_assert (mips_is_imm16(offset
));
4815 if (MIPS_LMF_IREGMASK
& (1 << i
))
4816 MIPS_SW (code
, i
, mips_sp
, offset
);
4821 /* Save float registers */
4822 if (fregs_to_save
) {
4823 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
4824 if (fregs_to_save
& (1 << i
)) {
4825 g_assert (pos
< cfg
->stack_usage
- MIPS_STACK_ALIGNMENT
);
4826 g_assert (mips_is_imm16(pos
));
4827 mips_swc1 (code
, i
, mips_sp
, pos
);
4828 pos
+= sizeof (gulong
);
4833 if (method
->save_lmf
) {
4834 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
4835 int offset
= lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, fregs
[i
]);
4836 g_assert (mips_is_imm16(offset
));
4837 mips_swc1 (code
, i
, mips_sp
, offset
);
4842 if (cfg
->frame_reg
!= mips_sp
) {
4843 MIPS_MOVE (code
, cfg
->frame_reg
, mips_sp
);
4844 mono_emit_unwind_op_def_cfa (cfg
, code
, cfg
->frame_reg
, cfa_offset
);
4846 if (method
->save_lmf
) {
4847 int offset
= lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, iregs
[cfg
->frame_reg
]);
4848 g_assert (mips_is_imm16(offset
));
4849 MIPS_SW (code
, cfg
->frame_reg
, mips_sp
, offset
);
4853 /* store runtime generic context */
4854 if (cfg
->rgctx_var
) {
4855 MonoInst
*ins
= cfg
->rgctx_var
;
4857 g_assert (ins
->opcode
== OP_REGOFFSET
);
4859 g_assert (mips_is_imm16 (ins
->inst_offset
));
4860 mips_sw (code
, MONO_ARCH_RGCTX_REG
, ins
->inst_basereg
, ins
->inst_offset
);
4863 /* load arguments allocated to register from the stack */
4866 if (!cfg
->arch
.cinfo
)
4867 cfg
->arch
.cinfo
= get_call_info (cfg
->mempool
, sig
);
4868 cinfo
= cfg
->arch
.cinfo
;
4870 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
4871 ArgInfo
*ainfo
= &cinfo
->ret
;
4872 inst
= cfg
->vret_addr
;
4873 if (inst
->opcode
== OP_REGVAR
)
4874 MIPS_MOVE (code
, inst
->dreg
, ainfo
->reg
);
4875 else if (mips_is_imm16 (inst
->inst_offset
)) {
4876 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4878 mips_load_const (code
, mips_at
, inst
->inst_offset
);
4879 mips_addu (code
, mips_at
, mips_at
, inst
->inst_basereg
);
4880 mips_sw (code
, ainfo
->reg
, mips_at
, 0);
4884 if (sig
->call_convention
== MONO_CALL_VARARG
) {
4885 ArgInfo
*cookie
= &cinfo
->sig_cookie
;
4886 int offset
= alloc_size
+ cookie
->offset
;
4888 /* Save the sig cookie address */
4889 g_assert (cookie
->storage
== ArgOnStack
);
4891 g_assert (mips_is_imm16(offset
));
4892 mips_addi (code
, mips_at
, cfg
->frame_reg
, offset
);
4893 mips_sw (code
, mips_at
, cfg
->frame_reg
, cfg
->sig_cookie
- alloc2_size
);
4896 /* Keep this in sync with emit_load_volatile_arguments */
4897 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4898 ArgInfo
*ainfo
= cinfo
->args
+ i
;
4899 inst
= cfg
->args
[pos
];
4901 if (cfg
->verbose_level
> 2)
4902 g_print ("Saving argument %d (type: %d)\n", i
, ainfo
->storage
);
4903 if (inst
->opcode
== OP_REGVAR
) {
4904 /* Argument ends up in a register */
4905 if (ainfo
->storage
== ArgInIReg
)
4906 MIPS_MOVE (code
, inst
->dreg
, ainfo
->reg
);
4907 else if (ainfo
->storage
== ArgInFReg
) {
4908 g_assert_not_reached();
4910 ppc_fmr (code
, inst
->dreg
, ainfo
->reg
);
4913 else if (ainfo
->storage
== ArgOnStack
) {
4914 int offset
= cfg
->stack_usage
+ ainfo
->offset
;
4915 g_assert (mips_is_imm16(offset
));
4916 mips_lw (code
, inst
->dreg
, mips_sp
, offset
);
4918 g_assert_not_reached ();
4920 if (cfg
->verbose_level
> 2)
4921 g_print ("Argument %d assigned to register %s\n", pos
, mono_arch_regname (inst
->dreg
));
4923 /* Argument ends up on the stack */
4924 if (ainfo
->storage
== ArgInIReg
) {
4926 /* Incoming parameters should be above this frame */
4927 if (cfg
->verbose_level
> 2)
4928 g_print ("stack slot at %d of %d+%d\n",
4929 inst
->inst_offset
, alloc_size
, alloc2_size
);
4930 /* g_assert (inst->inst_offset >= alloc_size); */
4931 g_assert (inst
->inst_basereg
== cfg
->frame_reg
);
4932 basereg_offset
= inst
->inst_offset
- alloc2_size
;
4933 g_assert (mips_is_imm16 (basereg_offset
));
4934 switch (ainfo
->size
) {
4936 mips_sb (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
);
4939 mips_sh (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
);
4943 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
);
4946 #if (SIZEOF_REGISTER == 4)
4947 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
+ ls_word_offset
);
4948 mips_sw (code
, ainfo
->reg
+ 1, inst
->inst_basereg
, basereg_offset
+ ms_word_offset
);
4949 #elif (SIZEOF_REGISTER == 8)
4950 mips_sd (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
);
4954 g_assert_not_reached ();
4957 } else if (ainfo
->storage
== ArgOnStack
) {
4959 * Argument comes in on the stack, and ends up on the stack
4960 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4961 * 8 and 16 bit quantities. Shorten them in place.
4963 g_assert (mips_is_imm16 (inst
->inst_offset
));
4964 switch (ainfo
->size
) {
4966 mips_lw (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4967 mips_sb (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4970 mips_lw (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4971 mips_sh (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4978 g_assert_not_reached ();
4980 } else if (ainfo
->storage
== ArgInFReg
) {
4981 g_assert (mips_is_imm16 (inst
->inst_offset
));
4982 g_assert (mips_is_imm16 (inst
->inst_offset
+4));
4983 if (ainfo
->size
== 8) {
4984 #if _MIPS_SIM == _ABIO32
4985 mips_swc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+ ls_word_offset
);
4986 mips_swc1 (code
, ainfo
->reg
+1, inst
->inst_basereg
, inst
->inst_offset
+ ms_word_offset
);
4987 #elif _MIPS_SIM == _ABIN32
4988 mips_sdc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4991 else if (ainfo
->size
== 4)
4992 mips_swc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4994 g_assert_not_reached ();
4995 } else if (ainfo
->storage
== ArgStructByVal
) {
4997 int doffset
= inst
->inst_offset
;
4999 g_assert (mips_is_imm16 (inst
->inst_offset
));
5000 g_assert (mips_is_imm16 (inst
->inst_offset
+ ainfo
->size
* sizeof (target_mgreg_t
)));
5001 /* Push the argument registers into their stack slots */
5002 for (i
= 0; i
< ainfo
->size
; ++i
) {
5003 g_assert (mips_is_imm16(doffset
));
5004 MIPS_SW (code
, ainfo
->reg
+ i
, inst
->inst_basereg
, doffset
);
5005 doffset
+= SIZEOF_REGISTER
;
5007 } else if (ainfo
->storage
== ArgStructByAddr
) {
5008 g_assert (mips_is_imm16 (inst
->inst_offset
));
5009 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5010 code
= emit_memcpy (code
, ainfo
->vtsize
* sizeof (target_mgreg_t
), inst
->inst_basereg
, inst
->inst_offset
, ainfo
->reg
, 0);
5012 g_assert_not_reached ();
5017 if (method
->save_lmf
) {
5018 mips_load_const (code
, mips_at
, MIPS_LMF_MAGIC1
);
5019 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, magic
));
5021 /* This can/will clobber the a0-a3 registers */
5022 mips_call (code
, mips_t9
, (gpointer
)mono_get_lmf_addr
);
5024 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5025 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
)));
5026 mips_sw (code
, mips_v0
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
5027 /* new_lmf->previous_lmf = *lmf_addr */
5028 mips_lw (code
, mips_at
, mips_v0
, 0);
5029 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
)));
5030 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
5031 /* *(lmf_addr) = sp + lmf_offset */
5032 g_assert (mips_is_imm16(lmf_offset
));
5033 mips_addiu (code
, mips_at
, mips_sp
, lmf_offset
);
5034 mips_sw (code
, mips_at
, mips_v0
, 0);
5036 /* save method info */
5037 mips_load_const (code
, mips_at
, method
);
5038 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, method
)));
5039 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, method
));
5041 /* save the current IP */
5042 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_IP
, NULL
);
5043 mips_load_const (code
, mips_at
, 0x01010101);
5044 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, eip
));
5048 if (mips_is_imm16 (-alloc2_size
)) {
5049 mips_addu (code
, mips_sp
, mips_sp
, -alloc2_size
);
5052 mips_load_const (code
, mips_at
, -alloc2_size
);
5053 mips_addu (code
, mips_sp
, mips_sp
, mips_at
);
5055 alloc_size
+= alloc2_size
;
5056 cfa_offset
+= alloc2_size
;
5057 if (cfg
->frame_reg
!= mips_sp
)
5058 MIPS_MOVE (code
, cfg
->frame_reg
, mips_sp
);
5060 mono_emit_unwind_op_def_cfa_offset (cfg
, code
, cfa_offset
);
5063 set_code_cursor (cfg
, code
);
5069 mono_arch_emit_epilog_sub (MonoCompile
*cfg
)
5071 guint8
*code
= NULL
;
5072 MonoMethod
*method
= cfg
->method
;
5074 int max_epilog_size
= 16 + 20*4;
5075 int alloc2_size
= 0;
5076 guint32 iregs_to_restore
;
5078 guint32 fregs_to_restore
;
5081 if (cfg
->method
->save_lmf
)
5082 max_epilog_size
+= 128;
5084 realloc_code (cfg
, max_epilog_size
);
5086 code
= cfg
->native_code
+ cfg
->code_len
;
5088 if (cfg
->frame_reg
!= mips_sp
) {
5089 MIPS_MOVE (code
, mips_sp
, cfg
->frame_reg
);
5091 /* If the stack frame is really large, deconstruct it in two steps */
5092 if (cfg
->stack_usage
> ((1 << 15) - 1024)) {
5093 alloc2_size
= cfg
->stack_usage
- 1024;
5094 /* partially deconstruct the stack */
5095 mips_load_const (code
, mips_at
, alloc2_size
);
5096 mips_addu (code
, mips_sp
, mips_sp
, mips_at
);
5098 pos
= cfg
->arch
.iregs_offset
- alloc2_size
;
5099 iregs_to_restore
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
5100 if (iregs_to_restore
) {
5101 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
5102 if (iregs_to_restore
& (1 << i
)) {
5103 g_assert (mips_is_imm16(pos
));
5104 MIPS_LW (code
, i
, mips_sp
, pos
);
5105 pos
+= SIZEOF_REGISTER
;
5112 fregs_to_restore
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
5114 fregs_to_restore
= MONO_ARCH_CALLEE_SAVED_FREGS
;
5115 fregs_to_restore
|= (fregs_to_restore
<< 1);
5117 if (fregs_to_restore
) {
5118 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
5119 if (fregs_to_restore
& (1 << i
)) {
5120 g_assert (pos
< cfg
->stack_usage
- MIPS_STACK_ALIGNMENT
);
5121 g_assert (mips_is_imm16(pos
));
5122 mips_lwc1 (code
, i
, mips_sp
, pos
);
5129 /* Unlink the LMF if necessary */
5130 if (method
->save_lmf
) {
5131 int lmf_offset
= cfg
->arch
.lmf_offset
;
5133 /* t0 = current_lmf->previous_lmf */
5134 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
)));
5135 mips_lw (code
, mips_temp
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
5137 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
)));
5138 mips_lw (code
, mips_t1
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
5139 /* (*lmf_addr) = previous_lmf */
5140 mips_sw (code
, mips_temp
, mips_t1
, 0);
5144 /* Restore the fp */
5145 mips_lw (code
, mips_fp
, mips_sp
, cfg
->stack_usage
+ MIPS_FP_ADDR_OFFSET
);
5148 if ((cfg
->flags
& MONO_CFG_HAS_CALLS
) || ALWAYS_SAVE_RA
) {
5149 g_assert (mips_is_imm16(cfg
->stack_usage
- alloc2_size
+ MIPS_RET_ADDR_OFFSET
));
5150 mips_lw (code
, mips_ra
, mips_sp
, cfg
->stack_usage
- alloc2_size
+ MIPS_RET_ADDR_OFFSET
);
5152 /* Restore the stack pointer */
5153 g_assert (mips_is_imm16(cfg
->stack_usage
- alloc2_size
));
5154 mips_addiu (code
, mips_sp
, mips_sp
, cfg
->stack_usage
- alloc2_size
);
5156 /* Caller will emit either return or tail-call sequence */
5158 set_code_cursor (cfg
, code
);
5164 mono_arch_emit_epilog (MonoCompile
*cfg
)
5166 guint8
*code
= mono_arch_emit_epilog_sub (cfg
);
5168 mips_jr (code
, mips_ra
);
5171 set_code_cursor (cfg
, code
);
5174 /* remove once throw_exception_by_name is eliminated */
5177 exception_id_by_name (const char *name
)
5179 if (strcmp (name
, "IndexOutOfRangeException") == 0)
5180 return MONO_EXC_INDEX_OUT_OF_RANGE
;
5181 if (strcmp (name
, "OverflowException") == 0)
5182 return MONO_EXC_OVERFLOW
;
5183 if (strcmp (name
, "ArithmeticException") == 0)
5184 return MONO_EXC_ARITHMETIC
;
5185 if (strcmp (name
, "DivideByZeroException") == 0)
5186 return MONO_EXC_DIVIDE_BY_ZERO
;
5187 if (strcmp (name
, "InvalidCastException") == 0)
5188 return MONO_EXC_INVALID_CAST
;
5189 if (strcmp (name
, "NullReferenceException") == 0)
5190 return MONO_EXC_NULL_REF
;
5191 if (strcmp (name
, "ArrayTypeMismatchException") == 0)
5192 return MONO_EXC_ARRAY_TYPE_MISMATCH
;
5193 if (strcmp (name
, "ArgumentException") == 0)
5194 return MONO_EXC_ARGUMENT
;
5195 g_error ("Unknown intrinsic exception %s\n", name
);
5201 mono_arch_emit_exceptions (MonoCompile
*cfg
)
5204 MonoJumpInfo
*patch_info
;
5207 const guint8
* exc_throw_pos
[MONO_EXC_INTRINS_NUM
] = {NULL
};
5208 guint8 exc_throw_found
[MONO_EXC_INTRINS_NUM
] = {0};
5209 int max_epilog_size
= 50;
5211 /* count the number of exception infos */
5214 * make sure we have enough space for exceptions
5215 * 24 is the simulated call to throw_exception_by_name
5217 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5219 if (patch_info
->type
== MONO_PATCH_INFO_EXC
) {
5220 i
= exception_id_by_name (patch_info
->data
.target
);
5221 g_assert (i
< MONO_EXC_INTRINS_NUM
);
5222 if (!exc_throw_found
[i
]) {
5223 max_epilog_size
+= 12;
5224 exc_throw_found
[i
] = TRUE
;
5230 code
= realloc_code (cfg
, max_epilog_size
);
5232 /* add code to raise exceptions */
5233 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5234 switch (patch_info
->type
) {
5235 case MONO_PATCH_INFO_EXC
: {
5237 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5239 i
= exception_id_by_name (patch_info
->data
.target
);
5240 g_assert (i
>= 0 && i
< MONO_EXC_INTRINS_NUM
);
5241 if (!exc_throw_pos
[i
]) {
5244 exc_throw_pos
[i
] = code
;
5245 //g_print ("exc: writing stub at %p\n", code);
5246 mips_load_const (code
, mips_a0
, patch_info
->data
.target
);
5247 addr
= (guint32
) mono_arch_get_throw_exception_by_name ();
5248 mips_load_const (code
, mips_t9
, addr
);
5249 mips_jr (code
, mips_t9
);
5252 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5254 /* Turn into a Relative patch, pointing at code stub */
5255 patch_info
->type
= MONO_PATCH_INFO_METHOD_REL
;
5256 patch_info
->data
.offset
= exc_throw_pos
[i
] - cfg
->native_code
;
5258 g_assert_not_reached();
5268 set_code_cursor (cfg
, code
);
5273 mono_arch_finish_init (void)
5278 mono_arch_free_jit_tls_data (MonoJitTlsData
*tls
)
5283 mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
, int this_reg
, int this_type
, int vt_reg
)
5285 int this_dreg
= mips_a0
;
5288 this_dreg
= mips_a1
;
5290 /* add the this argument */
5291 if (this_reg
!= -1) {
5293 MONO_INST_NEW (cfg
, this_ins
, OP_MOVE
);
5294 this_ins
->type
= this_type
;
5295 this_ins
->sreg1
= this_reg
;
5296 this_ins
->dreg
= mono_alloc_ireg (cfg
);
5297 mono_bblock_add_inst (cfg
->cbb
, this_ins
);
5298 mono_call_inst_add_outarg_reg (cfg
, inst
, this_ins
->dreg
, this_dreg
, FALSE
);
5303 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
5304 vtarg
->type
= STACK_MP
;
5305 vtarg
->sreg1
= vt_reg
;
5306 vtarg
->dreg
= mono_alloc_ireg (cfg
);
5307 mono_bblock_add_inst (cfg
->cbb
, vtarg
);
5308 mono_call_inst_add_outarg_reg (cfg
, inst
, vtarg
->dreg
, mips_a0
, FALSE
);
5313 mono_arch_get_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
5315 MonoInst
*ins
= NULL
;
5321 mono_arch_emit_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
5327 mono_arch_context_get_int_reg (MonoContext
*ctx
, int reg
)
5329 return ctx
->sc_regs
[reg
];
5332 #define ENABLE_WRONG_METHOD_CHECK 0
5334 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5335 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5337 #define LOADSTORE_SIZE 4
5338 #define JUMP_IMM_SIZE 16
5339 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5340 #define LOAD_CONST_SIZE 8
5341 #define JUMP_JR_SIZE 8
5344 * LOCKING: called with the domain lock held
5347 mono_arch_build_imt_trampoline (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
,
5348 gpointer fail_tramp
)
5352 guint8
*code
, *start
, *patch
;
5354 for (i
= 0; i
< count
; ++i
) {
5355 MonoIMTCheckItem
*item
= imt_entries
[i
];
5357 if (item
->is_equals
) {
5358 if (item
->check_target_idx
) {
5359 item
->chunk_size
+= LOAD_CONST_SIZE
+ BR_SIZE
+ JUMP_JR_SIZE
;
5360 if (item
->has_target_code
)
5361 item
->chunk_size
+= LOAD_CONST_SIZE
;
5363 item
->chunk_size
+= LOADSTORE_SIZE
;
5366 item
->chunk_size
+= LOAD_CONST_SIZE
+ BR_SIZE
+ JUMP_IMM32_SIZE
+
5367 LOADSTORE_SIZE
+ JUMP_IMM32_SIZE
;
5368 if (!item
->has_target_code
)
5369 item
->chunk_size
+= LOADSTORE_SIZE
;
5371 item
->chunk_size
+= LOADSTORE_SIZE
+ JUMP_JR_SIZE
;
5372 #if ENABLE_WRONG_METHOD_CHECK
5373 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
+ 4;
5378 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
;
5379 imt_entries
[item
->check_target_idx
]->compare_done
= TRUE
;
5381 size
+= item
->chunk_size
;
5383 /* the initial load of the vtable address */
5384 size
+= MIPS_LOAD_SEQUENCE_LENGTH
;
5386 code
= mono_method_alloc_generic_virtual_trampoline (domain
, size
);
5388 code
= mono_domain_code_reserve (domain
, size
);
5392 /* t7 points to the vtable */
5393 mips_load_const (code
, mips_t7
, (gsize
)(& (vtable
->vtable
[0])));
5395 for (i
= 0; i
< count
; ++i
) {
5396 MonoIMTCheckItem
*item
= imt_entries
[i
];
5398 item
->code_target
= code
;
5399 if (item
->is_equals
) {
5400 if (item
->check_target_idx
) {
5401 mips_load_const (code
, mips_temp
, (gsize
)item
->key
);
5402 item
->jmp_code
= code
;
5403 mips_bne (code
, mips_temp
, MONO_ARCH_IMT_REG
, 0);
5405 if (item
->has_target_code
) {
5406 mips_load_const (code
, mips_t9
,
5407 item
->value
.target_code
);
5410 mips_lw (code
, mips_t9
, mips_t7
,
5411 (sizeof (target_mgreg_t
) * item
->value
.vtable_slot
));
5413 mips_jr (code
, mips_t9
);
5417 mips_load_const (code
, mips_temp
, (gsize
)item
->key
);
5419 mips_bne (code
, mips_temp
, MONO_ARCH_IMT_REG
, 0);
5421 if (item
->has_target_code
) {
5422 mips_load_const (code
, mips_t9
,
5423 item
->value
.target_code
);
5426 mips_load_const (code
, mips_at
,
5427 & (vtable
->vtable
[item
->value
.vtable_slot
]));
5428 mips_lw (code
, mips_t9
, mips_at
, 0);
5430 mips_jr (code
, mips_t9
);
5432 mips_patch ((guint32
*)(void *)patch
, (guint32
)code
);
5433 mips_load_const (code
, mips_t9
, fail_tramp
);
5434 mips_jr (code
, mips_t9
);
5437 /* enable the commented code to assert on wrong method */
5438 #if ENABLE_WRONG_METHOD_CHECK
5439 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5440 ppc_compare_log (code
, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5442 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5444 mips_lw (code
, mips_t9
, mips_t7
,
5445 (sizeof (target_mgreg_t
) * item
->value
.vtable_slot
));
5446 mips_jr (code
, mips_t9
);
5449 #if ENABLE_WRONG_METHOD_CHECK
5450 ppc_patch (patch
, code
);
5456 mips_load_const (code
, mips_temp
, (gulong
)item
->key
);
5457 mips_slt (code
, mips_temp
, MONO_ARCH_IMT_REG
, mips_temp
);
5459 item
->jmp_code
= code
;
5460 mips_beq (code
, mips_temp
, mips_zero
, 0);
5464 /* patch the branches to get to the target items */
5465 for (i
= 0; i
< count
; ++i
) {
5466 MonoIMTCheckItem
*item
= imt_entries
[i
];
5467 if (item
->jmp_code
&& item
->check_target_idx
) {
5468 mips_patch ((guint32
*)item
->jmp_code
,
5469 (guint32
)imt_entries
[item
->check_target_idx
]->code_target
);
5474 UnlockedAdd (&mono_stats
.imt_trampolines_size
, code
- start
);
5475 g_assert (code
- start
<= size
);
5476 mono_arch_flush_icache (start
, size
);
5477 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE
, NULL
));
5479 mono_tramp_info_register (mono_tramp_info_create (NULL
, start
, code
- start
, NULL
, NULL
), domain
);
5485 mono_arch_find_imt_method (host_mgreg_t
*regs
, guint8
*code
)
5487 return (MonoMethod
*) regs
[MONO_ARCH_IMT_REG
];
5491 mono_arch_find_static_call_vtable (host_mgreg_t
*regs
, guint8
*code
)
5493 return (MonoVTable
*) regs
[MONO_ARCH_RGCTX_REG
];
5496 /* Soft Debug support */
5497 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5500 * mono_arch_set_breakpoint:
5502 * See mini-amd64.c for docs.
5505 mono_arch_set_breakpoint (MonoJitInfo
*ji
, guint8
*ip
)
5508 guint32 addr
= (guint32
)bp_trigger_page
;
5510 mips_load_const (code
, mips_t9
, addr
);
5511 mips_lw (code
, mips_t9
, mips_t9
, 0);
5513 mono_arch_flush_icache (ip
, code
- ip
);
5517 * mono_arch_clear_breakpoint:
5519 * See mini-amd64.c for docs.
5522 mono_arch_clear_breakpoint (MonoJitInfo
*ji
, guint8
*ip
)
5530 mono_arch_flush_icache (ip
, code
- ip
);
5534 * mono_arch_start_single_stepping:
5536 * See mini-amd64.c for docs.
5539 mono_arch_start_single_stepping (void)
5541 mono_mprotect (ss_trigger_page
, mono_pagesize (), 0);
5545 * mono_arch_stop_single_stepping:
5547 * See mini-amd64.c for docs.
5550 mono_arch_stop_single_stepping (void)
5552 mono_mprotect (ss_trigger_page
, mono_pagesize (), MONO_MMAP_READ
);
5556 * mono_arch_is_single_step_event:
5558 * See mini-amd64.c for docs.
5561 mono_arch_is_single_step_event (void *info
, void *sigctx
)
5563 siginfo_t
* sinfo
= (siginfo_t
*) info
;
5564 /* Sometimes the address is off by 4 */
5565 if (sinfo
->si_addr
>= ss_trigger_page
&& (guint8
*)sinfo
->si_addr
<= (guint8
*)ss_trigger_page
+ 128)
5572 * mono_arch_is_breakpoint_event:
5574 * See mini-amd64.c for docs.
5577 mono_arch_is_breakpoint_event (void *info
, void *sigctx
)
5579 siginfo_t
* sinfo
= (siginfo_t
*) info
;
5580 /* Sometimes the address is off by 4 */
5581 if (sinfo
->si_addr
>= bp_trigger_page
&& (guint8
*)sinfo
->si_addr
<= (guint8
*)bp_trigger_page
+ 128)
5588 * mono_arch_skip_breakpoint:
5590 * See mini-amd64.c for docs.
5593 mono_arch_skip_breakpoint (MonoContext
*ctx
, MonoJitInfo
*ji
)
5595 MONO_CONTEXT_SET_IP (ctx
, (guint8
*)MONO_CONTEXT_GET_IP (ctx
) + 4);
5599 * mono_arch_skip_single_step:
5601 * See mini-amd64.c for docs.
5604 mono_arch_skip_single_step (MonoContext
*ctx
)
5606 MONO_CONTEXT_SET_IP (ctx
, (guint8
*)MONO_CONTEXT_GET_IP (ctx
) + 4);
5610 * mono_arch_get_seq_point_info:
5612 * See mini-amd64.c for docs.
5615 mono_arch_get_seq_point_info (MonoDomain
*domain
, guint8
*code
)
5621 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5624 mono_arch_opcode_supported (int opcode
)
5630 mono_arch_tailcall_supported (MonoCompile
*cfg
, MonoMethodSignature
*caller_sig
, MonoMethodSignature
*callee_sig
, gboolean virtual_
)