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"
33 #include "mono/utils/mono-tls-inline.h"
35 #define SAVE_FP_REGS 0
37 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
39 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
40 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
41 remember to update cpu-mips.md if you change this */
43 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
44 #define mips_call(c,D,v) do { \
45 guint32 _target = (guint32)(v); \
46 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
47 mips_load_const (c, D, _target); \
48 mips_jalr (c, D, mips_ra); \
51 mips_jumpl (c, _target >> 2); \
63 /* This mutex protects architecture specific caches */
64 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
65 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
66 static mono_mutex_t mini_arch_mutex
;
68 /* Whenever the host is little-endian */
69 static int little_endian
;
70 /* Index of ms word/register */
71 static int ls_word_idx
;
72 /* Index of ls word/register */
73 static int ms_word_idx
;
74 /* Same for offsets */
75 static int ls_word_offset
;
76 static int ms_word_offset
;
79 * The code generated for sequence points reads from this location, which is
80 * made read-only when single stepping is enabled.
82 static gpointer ss_trigger_page
;
84 /* Enabled breakpoints read from this trigger page */
85 static gpointer bp_trigger_page
;
88 #define DEBUG(a) if (cfg->verbose_level > 1) a
94 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
96 code = mips_emit_exc_by_name (code, exc_name); \
97 cfg->bb_exit->max_offset += 16; \
100 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
102 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
103 inst->type = STACK_R8; \
105 inst->inst_p0 = (void*)(addr); \
106 mono_bblock_add_inst (cfg->cbb, inst); \
109 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
110 || ((ins)->opcode == OP_ICOMPARE) \
111 || ((ins)->opcode == OP_LCOMPARE)))
112 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
113 || ((ins)->opcode == OP_ICOMPARE_IMM) \
114 || ((ins)->opcode == OP_LCOMPARE_IMM)))
116 #define INS_REWRITE(ins, op, _s1, _s2) do { \
119 ins->opcode = (op); \
124 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
126 ins->opcode = (op); \
128 ins->inst_imm = (_imm); \
132 typedef struct InstList InstList
;
150 guint16 vtsize
; /* in param area */
153 guint8 size
: 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
162 gboolean vtype_retaddr
;
171 void patch_lui_addiu(guint32
*ip
, guint32 val
);
173 guint8
*mono_arch_emit_epilog_sub (MonoCompile
*cfg
);
174 guint8
*mips_emit_cond_branch (MonoCompile
*cfg
, guint8
*code
, int op
, MonoInst
*ins
);
175 void mips_adjust_stackframe(MonoCompile
*cfg
);
176 void mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
, int this_reg
, int this_type
, int vt_reg
);
177 MonoInst
*mono_arch_get_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
);
180 /* Not defined in asm/cachectl.h */
181 int cacheflush(char *addr
, int nbytes
, int cache
);
184 mono_arch_flush_icache (guint8
*code
, gint size
)
186 /* Linux/MIPS specific */
187 cacheflush ((char*)code
, size
, BCACHE
);
191 mono_arch_flush_register_windows (void)
196 mono_arch_is_inst_imm (int opcode
, int imm_opcode
, gint64 imm
)
202 mips_emit_exc_by_name(guint8
*code
, const char *name
)
205 MonoClass
*exc_class
;
207 exc_class
= mono_class_load_from_name (mono_defaults
.corlib
, "System", name
);
209 mips_load_const (code
, mips_a0
, m_class_get_type_token (exc_class
));
210 addr
= mono_get_throw_corlib_exception ();
211 mips_call (code
, mips_t9
, addr
);
216 mips_emit_load_const (guint8
*code
, int dreg
, target_mgreg_t v
)
218 if (mips_is_imm16 (v
))
219 mips_addiu (code
, dreg
, mips_zero
, ((guint32
)v
) & 0xffff);
221 #if SIZEOF_REGISTER == 8
223 /* v is not a sign-extended 32-bit value */
224 mips_lui (code
, dreg
, mips_zero
, (guint32
)((v
>> (32+16)) & 0xffff));
225 mips_ori (code
, dreg
, dreg
, (guint32
)((v
>> (32)) & 0xffff));
226 mips_dsll (code
, dreg
, dreg
, 16);
227 mips_ori (code
, dreg
, dreg
, (guint32
)((v
>> (16)) & 0xffff));
228 mips_dsll (code
, dreg
, dreg
, 16);
229 mips_ori (code
, dreg
, dreg
, (guint32
)(v
& 0xffff));
233 if (((guint32
)v
) & (1 << 15)) {
234 mips_lui (code
, dreg
, mips_zero
, (((guint32
)v
)>>16)+1);
237 mips_lui (code
, dreg
, mips_zero
, (((guint32
)v
)>>16));
239 if (((guint32
)v
) & 0xffff)
240 mips_addiu (code
, dreg
, dreg
, ((guint32
)v
) & 0xffff);
246 mips_emit_cond_branch (MonoCompile
*cfg
, guint8
*code
, int op
, MonoInst
*ins
)
249 if (cfg
->arch
.long_branch
) {
252 /* Invert test and emit branch around jump */
255 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, br_offset
);
259 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, br_offset
);
263 mips_bltz (code
, ins
->sreg1
, br_offset
);
267 mips_blez (code
, ins
->sreg1
, br_offset
);
271 mips_bgtz (code
, ins
->sreg1
, br_offset
);
275 mips_bgez (code
, ins
->sreg1
, br_offset
);
279 g_assert_not_reached ();
281 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
282 MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
283 mips_lui (code
, mips_at
, mips_zero
, 0);
284 mips_addiu (code
, mips_at
, mips_at
, 0);
285 mips_jr (code
, mips_at
);
289 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
290 MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
293 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, 0);
297 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, 0);
301 mips_bgez (code
, ins
->sreg1
, 0);
305 mips_bgtz (code
, ins
->sreg1
, 0);
309 mips_blez (code
, ins
->sreg1
, 0);
313 mips_bltz (code
, ins
->sreg1
, 0);
317 g_assert_not_reached ();
323 /* XXX - big-endian dependent? */
325 patch_lui_addiu(guint32
*ip
, guint32 val
)
327 guint16
*__lui_addiu
= (guint16
*)(void *)(ip
);
330 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
331 ip
, ((guint32
*)ip
)[0], ((guint32
*)ip
)[1], val
);
334 if (((guint32
)(val
)) & (1 << 15))
335 __lui_addiu
[MINI_LS_WORD_IDX
] = ((((guint32
)(val
)) >> 16) & 0xffff) + 1;
337 __lui_addiu
[MINI_LS_WORD_IDX
] = (((guint32
)(val
)) >> 16) & 0xffff;
338 __lui_addiu
[MINI_LS_WORD_IDX
+ 2] = ((guint32
)(val
)) & 0xffff;
339 mono_arch_flush_icache ((guint8
*)ip
, 8);
344 mips_patch (guint32
*code
, guint32 target
)
347 guint32 op
= ins
>> 26;
348 guint32 diff
, offset
;
350 g_assert (trap_target
!= target
);
351 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
353 case 0x00: /* jr ra */
354 if (ins
== 0x3e00008)
356 g_assert_not_reached ();
360 g_assert (!(target
& 0x03));
361 g_assert ((target
& 0xfc000000) == (((guint32
)code
) & 0xfc000000));
362 ins
= (ins
& 0xfc000000) | (((target
) >> 2) & 0x03ffffff);
364 mono_arch_flush_icache ((guint8
*)code
, 4);
366 case 0x01: /* BLTZ */
369 case 0x06: /* BLEZ */
370 case 0x07: /* BGTZ */
371 case 0x11: /* bc1t */
372 diff
= target
- (guint32
)(code
+ 1);
373 g_assert (((diff
& 0x0003ffff) == diff
) || ((diff
| 0xfffc0000) == diff
));
374 g_assert (!(diff
& 0x03));
375 offset
= ((gint32
)diff
) >> 2;
376 if (((int)offset
) != ((int)(short)offset
))
377 g_assert (((int)offset
) == ((int)(short)offset
));
378 ins
= (ins
& 0xffff0000) | (offset
& 0x0000ffff);
380 mono_arch_flush_icache ((guint8
*)code
, 4);
382 case 0x0f: /* LUI / ADDIU pair */
383 g_assert ((code
[1] >> 26) == 0x9);
384 patch_lui_addiu (code
, target
);
385 mono_arch_flush_icache ((guint8
*)code
, 8);
389 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op
, ins
, code
);
390 g_assert_not_reached ();
394 static void mono_arch_compute_omit_fp (MonoCompile
*cfg
);
397 mono_arch_regname (int reg
) {
398 #if _MIPS_SIM == _ABIO32
399 static const char * rnames
[] = {
400 "zero", "at", "v0", "v1",
401 "a0", "a1", "a2", "a3",
402 "t0", "t1", "t2", "t3",
403 "t4", "t5", "t6", "t7",
404 "s0", "s1", "s2", "s3",
405 "s4", "s5", "s6", "s7",
406 "t8", "t9", "k0", "k1",
407 "gp", "sp", "fp", "ra"
409 #elif _MIPS_SIM == _ABIN32
410 static const char * rnames
[] = {
411 "zero", "at", "v0", "v1",
412 "a0", "a1", "a2", "a3",
413 "a4", "a5", "a6", "a7",
414 "t0", "t1", "t2", "t3",
415 "s0", "s1", "s2", "s3",
416 "s4", "s5", "s6", "s7",
417 "t8", "t9", "k0", "k1",
418 "gp", "sp", "fp", "ra"
421 if (reg
>= 0 && reg
< 32)
427 mono_arch_fregname (int reg
) {
428 static const char * rnames
[] = {
429 "f0", "f1", "f2", "f3",
430 "f4", "f5", "f6", "f7",
431 "f8", "f9", "f10", "f11",
432 "f12", "f13", "f14", "f15",
433 "f16", "f17", "f18", "f19",
434 "f20", "f21", "f22", "f23",
435 "f24", "f25", "f26", "f27",
436 "f28", "f29", "f30", "f31"
438 if (reg
>= 0 && reg
< 32)
443 /* this function overwrites at */
445 emit_memcpy (guint8
*code
, int size
, int dreg
, int doffset
, int sreg
, int soffset
)
447 /* XXX write a loop, not an unrolled loop */
449 mips_lw (code
, mips_at
, sreg
, soffset
);
450 mips_sw (code
, mips_at
, dreg
, doffset
);
459 * mono_arch_get_argument_info:
460 * @csig: a method signature
461 * @param_count: the number of parameters to consider
462 * @arg_info: an array to store the result infos
464 * Gathers information on parameters such as size, alignment and
465 * padding. arg_info should be large enought to hold param_count + 1 entries.
467 * Returns the size of the activation frame.
470 mono_arch_get_argument_info (MonoMethodSignature
*csig
, int param_count
, MonoJitArgumentInfo
*arg_info
)
472 int k
, frame_size
= 0;
473 guint32 size
, align
, pad
;
476 if (MONO_TYPE_ISSTRUCT (csig
->ret
)) {
477 frame_size
+= sizeof (target_mgreg_t
);
481 arg_info
[0].offset
= offset
;
484 frame_size
+= sizeof (target_mgreg_t
);
488 arg_info
[0].size
= frame_size
;
490 for (k
= 0; k
< param_count
; k
++) {
491 size
= mini_type_stack_size_full (csig
->params
[k
], &align
, csig
->pinvoke
);
493 /* ignore alignment for now */
496 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
497 arg_info
[k
].pad
= pad
;
499 arg_info
[k
+ 1].pad
= 0;
500 arg_info
[k
+ 1].size
= size
;
502 arg_info
[k
+ 1].offset
= offset
;
506 align
= MONO_ARCH_FRAME_ALIGNMENT
;
507 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
508 arg_info
[k
].pad
= pad
;
513 /* The delegate object plus 3 params */
514 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
517 get_delegate_invoke_impl (MonoTrampInfo
**info
, gboolean has_target
, gboolean param_count
)
519 guint8
*code
, *start
;
522 start
= code
= mono_global_codeman_reserve (16);
524 /* Replace the this argument with the target */
525 mips_lw (code
, mips_temp
, mips_a0
, MONO_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
526 mips_lw (code
, mips_a0
, mips_a0
, MONO_STRUCT_OFFSET (MonoDelegate
, target
));
527 mips_jr (code
, mips_temp
);
530 g_assert ((code
- start
) <= 16);
532 mono_arch_flush_icache (start
, 16);
533 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE
, NULL
));
537 size
= 16 + param_count
* 4;
538 start
= code
= mono_global_codeman_reserve (size
);
540 mips_lw (code
, mips_temp
, mips_a0
, MONO_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
541 /* slide down the arguments */
542 for (i
= 0; i
< param_count
; ++i
) {
543 mips_move (code
, mips_a0
+ i
, mips_a0
+ i
+ 1);
545 mips_jr (code
, mips_temp
);
548 g_assert ((code
- start
) <= size
);
550 mono_arch_flush_icache (start
, size
);
551 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE
, NULL
));
555 *info
= mono_tramp_info_create ("delegate_invoke_impl_has_target", start
, code
- start
, NULL
, NULL
);
557 char *name
= g_strdup_printf ("delegate_invoke_impl_target_%d", param_count
);
558 *info
= mono_tramp_info_create (name
, start
, code
- start
, NULL
, NULL
);
566 * mono_arch_get_delegate_invoke_impls:
568 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
572 mono_arch_get_delegate_invoke_impls (void)
578 get_delegate_invoke_impl (&info
, TRUE
, 0);
579 res
= g_slist_prepend (res
, info
);
581 for (i
= 0; i
<= MAX_ARCH_DELEGATE_PARAMS
; ++i
) {
582 get_delegate_invoke_impl (&info
, FALSE
, i
);
583 res
= g_slist_prepend (res
, info
);
590 mono_arch_get_delegate_invoke_impl (MonoMethodSignature
*sig
, gboolean has_target
)
592 guint8
*code
, *start
;
594 /* FIXME: Support more cases */
595 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
599 static guint8
* cached
= NULL
;
600 mono_mini_arch_lock ();
602 mono_mini_arch_unlock ();
606 if (mono_ee_features
.use_aot_trampolines
) {
607 start
= mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
610 start
= get_delegate_invoke_impl (&info
, TRUE
, 0);
611 mono_tramp_info_register (info
, NULL
);
614 mono_mini_arch_unlock ();
617 static guint8
* cache
[MAX_ARCH_DELEGATE_PARAMS
+ 1] = {NULL
};
620 if (sig
->param_count
> MAX_ARCH_DELEGATE_PARAMS
)
622 for (i
= 0; i
< sig
->param_count
; ++i
)
623 if (!mono_is_regsize_var (sig
->params
[i
]))
626 mono_mini_arch_lock ();
627 code
= cache
[sig
->param_count
];
629 mono_mini_arch_unlock ();
633 if (mono_ee_features
.use_aot_trampolines
) {
634 char *name
= g_strdup_printf ("delegate_invoke_impl_target_%d", sig
->param_count
);
635 start
= mono_aot_get_trampoline (name
);
639 start
= get_delegate_invoke_impl (&info
, FALSE
, sig
->param_count
);
640 mono_tramp_info_register (info
, NULL
);
642 cache
[sig
->param_count
] = start
;
643 mono_mini_arch_unlock ();
651 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
, int offset
, gboolean load_imt_reg
)
657 mono_arch_get_this_arg_from_call (host_mgreg_t
*regs
, guint8
*code
)
660 return (gpointer
)regs
[mips_a0
];
664 * Initialize the cpu to execute managed code.
667 mono_arch_cpu_init (void)
669 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
678 ls_word_offset
= ls_word_idx
* 4;
679 ms_word_offset
= ms_word_idx
* 4;
683 * Initialize architecture specific code.
686 mono_arch_init (void)
688 mono_os_mutex_init_recursive (&mini_arch_mutex
);
690 ss_trigger_page
= mono_valloc (NULL
, mono_pagesize (), MONO_MMAP_READ
, MONO_MEM_ACCOUNT_OTHER
);
691 bp_trigger_page
= mono_valloc (NULL
, mono_pagesize (), MONO_MMAP_READ
, MONO_MEM_ACCOUNT_OTHER
);
692 mono_mprotect (bp_trigger_page
, mono_pagesize (), 0);
696 * Cleanup architecture specific code.
699 mono_arch_cleanup (void)
701 mono_os_mutex_destroy (&mini_arch_mutex
);
705 mono_arch_have_fast_tls (void)
711 * This function returns the optimizations supported on this cpu.
714 mono_arch_cpu_optimizations (guint32
*exclude_mask
)
718 /* no mips-specific optimizations yet */
724 * This function test for all SIMD functions supported.
726 * Returns a bitmask corresponding to all supported versions.
730 mono_arch_cpu_enumerate_simd_versions (void)
732 /* SIMD is currently unimplemented */
737 mono_arch_get_allocatable_int_vars (MonoCompile
*cfg
)
742 for (i
= 0; i
< cfg
->num_varinfo
; i
++) {
743 MonoInst
*ins
= cfg
->varinfo
[i
];
744 MonoMethodVar
*vmv
= MONO_VARINFO (cfg
, i
);
747 if (vmv
->range
.first_use
.abs_pos
>= vmv
->range
.last_use
.abs_pos
)
750 if (ins
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
) || (ins
->opcode
!= OP_LOCAL
&& ins
->opcode
!= OP_ARG
))
753 /* we can only allocate 32 bit values */
754 if (mono_is_regsize_var (ins
->inst_vtype
)) {
755 g_assert (MONO_VARINFO (cfg
, i
)->reg
== -1);
756 g_assert (i
== vmv
->idx
);
757 vars
= mono_varlist_insert_sorted (cfg
, vars
, vmv
, FALSE
);
765 mono_arch_get_global_int_regs (MonoCompile
*cfg
)
769 regs
= g_list_prepend (regs
, (gpointer
)mips_s0
);
770 regs
= g_list_prepend (regs
, (gpointer
)mips_s1
);
771 regs
= g_list_prepend (regs
, (gpointer
)mips_s2
);
772 regs
= g_list_prepend (regs
, (gpointer
)mips_s3
);
773 regs
= g_list_prepend (regs
, (gpointer
)mips_s4
);
774 //regs = g_list_prepend (regs, (gpointer)mips_s5);
775 regs
= g_list_prepend (regs
, (gpointer
)mips_s6
);
776 regs
= g_list_prepend (regs
, (gpointer
)mips_s7
);
782 * mono_arch_regalloc_cost:
784 * Return the cost, in number of memory references, of the action of
785 * allocating the variable VMV into a register during global register
789 mono_arch_regalloc_cost (MonoCompile
*cfg
, MonoMethodVar
*vmv
)
796 args_onto_stack (CallInfo
*info
)
798 g_assert (!info
->on_stack
);
799 g_assert (info
->stack_size
<= MIPS_STACK_PARAM_OFFSET
);
800 info
->on_stack
= TRUE
;
801 info
->stack_size
= MIPS_STACK_PARAM_OFFSET
;
804 #if _MIPS_SIM == _ABIO32
806 * O32 calling convention version
810 add_int32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
811 /* First, see if we need to drop onto the stack */
812 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
813 args_onto_stack (info
);
815 /* Now, place the argument */
816 if (info
->on_stack
) {
817 ainfo
->storage
= ArgOnStack
;
818 ainfo
->reg
= mips_sp
; /* in the caller */
819 ainfo
->offset
= info
->stack_size
;
822 ainfo
->storage
= ArgInIReg
;
823 ainfo
->reg
= info
->gr
;
825 info
->gr_passed
= TRUE
;
827 info
->stack_size
+= 4;
831 add_int64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
832 /* First, see if we need to drop onto the stack */
833 if (!info
->on_stack
&& info
->gr
+1 > MIPS_LAST_ARG_REG
)
834 args_onto_stack (info
);
836 /* Now, place the argument */
837 if (info
->on_stack
) {
838 g_assert (info
->stack_size
% 4 == 0);
839 info
->stack_size
+= (info
->stack_size
% 8);
841 ainfo
->storage
= ArgOnStack
;
842 ainfo
->reg
= mips_sp
; /* in the caller */
843 ainfo
->offset
= info
->stack_size
;
846 // info->gr must be a0 or a2
847 info
->gr
+= (info
->gr
- MIPS_FIRST_ARG_REG
) % 2;
848 g_assert(info
->gr
<= MIPS_LAST_ARG_REG
);
850 ainfo
->storage
= ArgInIReg
;
851 ainfo
->reg
= info
->gr
;
853 info
->gr_passed
= TRUE
;
855 info
->stack_size
+= 8;
859 add_float32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
860 /* First, see if we need to drop onto the stack */
861 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
862 args_onto_stack (info
);
864 /* Now, place the argument */
865 if (info
->on_stack
) {
866 ainfo
->storage
= ArgOnStack
;
867 ainfo
->reg
= mips_sp
; /* in the caller */
868 ainfo
->offset
= info
->stack_size
;
871 /* Only use FP regs for args if no int args passed yet */
872 if (!info
->gr_passed
&& info
->fr
<= MIPS_LAST_FPARG_REG
) {
873 ainfo
->storage
= ArgInFReg
;
874 ainfo
->reg
= info
->fr
;
875 /* Even though it's a single-precision float, it takes up two FP regs */
877 /* FP and GP slots do not overlap */
881 /* Passing single-precision float arg in a GP register
882 * such as: func (0, 1.0, 2, 3);
883 * In this case, only one 'gr' register is consumed.
885 ainfo
->storage
= ArgInIReg
;
886 ainfo
->reg
= info
->gr
;
889 info
->gr_passed
= TRUE
;
892 info
->stack_size
+= 4;
896 add_float64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
897 /* First, see if we need to drop onto the stack */
898 if (!info
->on_stack
&& info
->gr
+1 > MIPS_LAST_ARG_REG
)
899 args_onto_stack (info
);
901 /* Now, place the argument */
902 if (info
->on_stack
) {
903 g_assert(info
->stack_size
% 4 == 0);
904 info
->stack_size
+= (info
->stack_size
% 8);
906 ainfo
->storage
= ArgOnStack
;
907 ainfo
->reg
= mips_sp
; /* in the caller */
908 ainfo
->offset
= info
->stack_size
;
911 /* Only use FP regs for args if no int args passed yet */
912 if (!info
->gr_passed
&& info
->fr
<= MIPS_LAST_FPARG_REG
) {
913 ainfo
->storage
= ArgInFReg
;
914 ainfo
->reg
= info
->fr
;
916 /* FP and GP slots do not overlap */
920 // info->gr must be a0 or a2
921 info
->gr
+= (info
->gr
- MIPS_FIRST_ARG_REG
) % 2;
922 g_assert(info
->gr
<= MIPS_LAST_ARG_REG
);
924 ainfo
->storage
= ArgInIReg
;
925 ainfo
->reg
= info
->gr
;
927 info
->gr_passed
= TRUE
;
930 info
->stack_size
+= 8;
932 #elif _MIPS_SIM == _ABIN32
934 * N32 calling convention version
938 add_int32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
939 /* First, see if we need to drop onto the stack */
940 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
941 args_onto_stack (info
);
943 /* Now, place the argument */
944 if (info
->on_stack
) {
945 ainfo
->storage
= ArgOnStack
;
946 ainfo
->reg
= mips_sp
; /* in the caller */
947 ainfo
->offset
= info
->stack_size
;
948 info
->stack_size
+= SIZEOF_REGISTER
;
951 ainfo
->storage
= ArgInIReg
;
952 ainfo
->reg
= info
->gr
;
954 info
->gr_passed
= TRUE
;
959 add_int64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
960 /* First, see if we need to drop onto the stack */
961 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
962 args_onto_stack (info
);
964 /* Now, place the argument */
965 if (info
->on_stack
) {
966 g_assert (info
->stack_size
% 4 == 0);
967 info
->stack_size
+= (info
->stack_size
% 8);
969 ainfo
->storage
= ArgOnStack
;
970 ainfo
->reg
= mips_sp
; /* in the caller */
971 ainfo
->offset
= info
->stack_size
;
972 info
->stack_size
+= SIZEOF_REGISTER
;
975 g_assert (info
->gr
<= MIPS_LAST_ARG_REG
);
977 ainfo
->storage
= ArgInIReg
;
978 ainfo
->reg
= info
->gr
;
980 info
->gr_passed
= TRUE
;
985 add_float32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
986 /* First, see if we need to drop onto the stack */
987 if (!info
->on_stack
) {
988 if (info
->gr
> MIPS_LAST_ARG_REG
)
989 args_onto_stack (info
);
990 else if (info
->fr
> MIPS_LAST_FPARG_REG
)
991 args_onto_stack (info
);
994 /* Now, place the argument */
995 if (info
->on_stack
) {
996 ainfo
->storage
= ArgOnStack
;
997 ainfo
->reg
= mips_sp
; /* in the caller */
998 ainfo
->offset
= info
->stack_size
;
999 info
->stack_size
+= FREG_SIZE
;
1002 ainfo
->storage
= ArgInFReg
;
1003 ainfo
->reg
= info
->fr
;
1005 /* FP and GP slots do not overlap */
1011 add_float64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
1012 /* First, see if we need to drop onto the stack */
1013 if (!info
->on_stack
) {
1014 if (info
->gr
> MIPS_LAST_ARG_REG
)
1015 args_onto_stack (info
);
1016 else if (info
->fr
> MIPS_LAST_FPARG_REG
)
1017 args_onto_stack (info
);
1020 /* Now, place the argument */
1021 if (info
->on_stack
) {
1022 g_assert(info
->stack_size
% 4 == 0);
1023 info
->stack_size
+= (info
->stack_size
% 8);
1025 ainfo
->storage
= ArgOnStack
;
1026 ainfo
->reg
= mips_sp
; /* in the caller */
1027 ainfo
->offset
= info
->stack_size
;
1028 info
->stack_size
+= FREG_SIZE
;
1031 ainfo
->storage
= ArgInFReg
;
1032 ainfo
->reg
= info
->fr
;
1034 /* FP and GP slots do not overlap */
1041 get_call_info (MonoMemPool
*mp
, MonoMethodSignature
*sig
)
1044 int n
= sig
->hasthis
+ sig
->param_count
;
1046 MonoType
* simpletype
;
1048 gboolean is_pinvoke
= sig
->pinvoke
;
1051 cinfo
= mono_mempool_alloc0 (mp
, sizeof (CallInfo
) + (sizeof (ArgInfo
) * n
));
1053 cinfo
= g_malloc0 (sizeof (CallInfo
) + (sizeof (ArgInfo
) * n
));
1055 cinfo
->fr
= MIPS_FIRST_FPARG_REG
;
1056 cinfo
->gr
= MIPS_FIRST_ARG_REG
;
1057 cinfo
->stack_size
= 0;
1059 DEBUG(printf("calculate_sizes\n"));
1061 cinfo
->vtype_retaddr
= MONO_TYPE_ISSTRUCT (sig
->ret
) ? TRUE
: FALSE
;
1065 /* handle returning a struct */
1066 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1067 cinfo
->struct_ret
= cinfo
->gr
;
1068 add_int32_arg (cinfo
, &cinfo
->ret
);
1072 add_int32_arg (cinfo
, cinfo
->args
+ n
);
1077 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1078 * the first argument, allowing 'this' to be always passed in the first arg reg.
1079 * Also do this if the first argument is a reference type, since virtual calls
1080 * are sometimes made using calli without sig->hasthis set, like in the delegate
1083 if (cinfo
->vtype_retaddr
&& !is_pinvoke
&& (sig
->hasthis
|| (sig
->param_count
> 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig
->params
[0]))))) {
1085 add_int32_arg (cinfo
, cinfo
->args
+ n
);
1088 add_int32_arg (cinfo
, cinfo
->args
+ sig
->hasthis
);
1092 add_int32_arg (cinfo
, &cinfo
->ret
);
1093 cinfo
->struct_ret
= cinfo
->ret
.reg
;
1097 add_int32_arg (cinfo
, cinfo
->args
+ n
);
1101 if (cinfo
->vtype_retaddr
) {
1102 add_int32_arg (cinfo
, &cinfo
->ret
);
1103 cinfo
->struct_ret
= cinfo
->ret
.reg
;
1108 DEBUG(printf("params: %d\n", sig
->param_count
));
1109 for (i
= pstart
; i
< sig
->param_count
; ++i
) {
1110 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1111 /* Prevent implicit arguments and sig_cookie from
1112 being passed in registers */
1113 args_onto_stack (cinfo
);
1114 /* Emit the signature cookie just before the implicit arguments */
1115 add_int32_arg (cinfo
, &cinfo
->sig_cookie
);
1117 DEBUG(printf("param %d: ", i
));
1118 simpletype
= mini_get_underlying_type (sig
->params
[i
]);
1119 switch (simpletype
->type
) {
1122 DEBUG(printf("1 byte\n"));
1123 cinfo
->args
[n
].size
= 1;
1124 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1129 DEBUG(printf("2 bytes\n"));
1130 cinfo
->args
[n
].size
= 2;
1131 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1136 DEBUG(printf("4 bytes\n"));
1137 cinfo
->args
[n
].size
= 4;
1138 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1144 case MONO_TYPE_FNPTR
:
1145 case MONO_TYPE_OBJECT
:
1146 cinfo
->args
[n
].size
= sizeof (target_mgreg_t
);
1147 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1150 case MONO_TYPE_GENERICINST
:
1151 if (!mono_type_generic_inst_is_valuetype (simpletype
)) {
1152 cinfo
->args
[n
].size
= sizeof (target_mgreg_t
);
1153 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1158 case MONO_TYPE_TYPEDBYREF
:
1159 case MONO_TYPE_VALUETYPE
: {
1162 int has_offset
= FALSE
;
1164 gint size
, alignment
;
1167 if (simpletype
->type
== MONO_TYPE_TYPEDBYREF
) {
1168 size
= MONO_ABI_SIZEOF (MonoTypedRef
);
1169 alignment
= sizeof (target_mgreg_t
);
1171 klass
= mono_class_from_mono_type_internal (sig
->params
[i
]);
1173 size
= mono_class_native_size (klass
, NULL
);
1175 size
= mono_class_value_size (klass
, NULL
);
1176 alignment
= mono_class_min_align (klass
);
1178 #if MIPS_PASS_STRUCTS_BY_VALUE
1179 /* Need to do alignment if struct contains long or double */
1180 if (alignment
> 4) {
1181 /* Drop onto stack *before* looking at
1182 stack_size, if required. */
1183 if (!cinfo
->on_stack
&& cinfo
->gr
> MIPS_LAST_ARG_REG
)
1184 args_onto_stack (cinfo
);
1185 if (cinfo
->stack_size
& (alignment
- 1)) {
1186 add_int32_arg (cinfo
, &dummy_arg
);
1188 g_assert (!(cinfo
->stack_size
& (alignment
- 1)));
1192 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1193 mono_class_native_size (sig
->params
[i
]->data
.klass
, NULL
),
1194 cinfo
->stack_size
, alignment
);
1196 nwords
= (size
+ sizeof (target_mgreg_t
) -1 ) / sizeof (target_mgreg_t
);
1197 g_assert (cinfo
->args
[n
].size
== 0);
1198 g_assert (cinfo
->args
[n
].vtsize
== 0);
1199 for (j
= 0; j
< nwords
; ++j
) {
1201 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1202 if (cinfo
->on_stack
)
1205 add_int32_arg (cinfo
, &dummy_arg
);
1206 if (!has_offset
&& cinfo
->on_stack
) {
1207 cinfo
->args
[n
].offset
= dummy_arg
.offset
;
1211 if (cinfo
->on_stack
)
1212 cinfo
->args
[n
].vtsize
+= 1;
1214 cinfo
->args
[n
].size
+= 1;
1216 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1217 cinfo
->args
[n
].storage
= ArgStructByVal
;
1219 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1220 cinfo
->args
[n
].storage
= ArgStructByAddr
;
1227 DEBUG(printf("8 bytes\n"));
1228 cinfo
->args
[n
].size
= 8;
1229 add_int64_arg (cinfo
, &cinfo
->args
[n
]);
1233 DEBUG(printf("R4\n"));
1234 cinfo
->args
[n
].size
= 4;
1235 add_float32_arg (cinfo
, &cinfo
->args
[n
]);
1239 DEBUG(printf("R8\n"));
1240 cinfo
->args
[n
].size
= 8;
1241 add_float64_arg (cinfo
, &cinfo
->args
[n
]);
1245 g_error ("Can't trampoline 0x%x", sig
->params
[i
]->type
);
1249 /* Handle the case where there are no implicit arguments */
1250 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1251 /* Prevent implicit arguments and sig_cookie from
1252 being passed in registers */
1253 args_onto_stack (cinfo
);
1254 /* Emit the signature cookie just before the implicit arguments */
1255 add_int32_arg (cinfo
, &cinfo
->sig_cookie
);
1259 simpletype
= mini_get_underlying_type (sig
->ret
);
1260 switch (simpletype
->type
) {
1270 case MONO_TYPE_FNPTR
:
1271 case MONO_TYPE_OBJECT
:
1272 cinfo
->ret
.reg
= mips_v0
;
1276 cinfo
->ret
.reg
= mips_v0
;
1280 cinfo
->ret
.reg
= mips_f0
;
1281 cinfo
->ret
.storage
= ArgInFReg
;
1283 case MONO_TYPE_GENERICINST
:
1284 if (!mono_type_generic_inst_is_valuetype (simpletype
)) {
1285 cinfo
->ret
.reg
= mips_v0
;
1289 case MONO_TYPE_VALUETYPE
:
1290 case MONO_TYPE_TYPEDBYREF
:
1292 case MONO_TYPE_VOID
:
1295 g_error ("Can't handle as return value 0x%x", sig
->ret
->type
);
1299 /* align stack size to 16 */
1300 cinfo
->stack_size
= (cinfo
->stack_size
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1302 cinfo
->stack_usage
= cinfo
->stack_size
;
1307 debug_omit_fp (void)
1310 return mono_debug_count ();
1317 * mono_arch_compute_omit_fp:
1318 * Determine whether the frame pointer can be eliminated.
1321 mono_arch_compute_omit_fp (MonoCompile
*cfg
)
1323 MonoMethodSignature
*sig
;
1324 MonoMethodHeader
*header
;
1328 if (cfg
->arch
.omit_fp_computed
)
1331 header
= cfg
->header
;
1333 sig
= mono_method_signature_internal (cfg
->method
);
1335 if (!cfg
->arch
.cinfo
)
1336 cfg
->arch
.cinfo
= get_call_info (cfg
->mempool
, sig
);
1337 cinfo
= cfg
->arch
.cinfo
;
1340 * FIXME: Remove some of the restrictions.
1342 cfg
->arch
.omit_fp
= TRUE
;
1343 cfg
->arch
.omit_fp_computed
= TRUE
;
1345 if (cfg
->disable_omit_fp
)
1346 cfg
->arch
.omit_fp
= FALSE
;
1347 if (!debug_omit_fp ())
1348 cfg
->arch
.omit_fp
= FALSE
;
1349 if (cfg
->method
->save_lmf
)
1350 cfg
->arch
.omit_fp
= FALSE
;
1351 if (cfg
->flags
& MONO_CFG_HAS_ALLOCA
)
1352 cfg
->arch
.omit_fp
= FALSE
;
1353 if (header
->num_clauses
)
1354 cfg
->arch
.omit_fp
= FALSE
;
1355 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
))
1356 cfg
->arch
.omit_fp
= FALSE
;
1358 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1359 * there are stack arguments.
1362 if (cinfo->stack_usage)
1363 cfg->arch.omit_fp = FALSE;
1367 for (i
= cfg
->locals_start
; i
< cfg
->num_varinfo
; i
++) {
1368 MonoInst
*ins
= cfg
->varinfo
[i
];
1371 locals_size
+= mono_type_size (ins
->inst_vtype
, &ialign
);
1374 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1378 * Set var information according to the calling convention. mips version.
1379 * The locals var stuff should most likely be split in another method.
1382 mono_arch_allocate_vars (MonoCompile
*cfg
)
1384 MonoMethodSignature
*sig
;
1385 MonoMethodHeader
*header
;
1387 int i
, offset
, size
, align
, curinst
;
1388 int frame_reg
= mips_sp
;
1389 guint32 iregs_to_save
= 0;
1391 guint32 fregs_to_restore
;
1395 sig
= mono_method_signature_internal (cfg
->method
);
1397 if (!cfg
->arch
.cinfo
)
1398 cfg
->arch
.cinfo
= get_call_info (cfg
->mempool
, sig
);
1399 cinfo
= cfg
->arch
.cinfo
;
1401 mono_arch_compute_omit_fp (cfg
);
1403 /* spill down, we'll fix it in a separate pass */
1404 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1406 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1407 * call convs needs to be handled this way.
1409 if (cfg
->flags
& MONO_CFG_HAS_VARARGS
)
1410 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (target_mgreg_t
)*8);
1412 /* gtk-sharp and other broken code will dllimport vararg functions even with
1413 * non-varargs signatures. Since there is little hope people will get this right
1414 * we assume they won't.
1416 if (cfg
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
1417 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (target_mgreg_t
)*8);
1419 /* a0-a3 always present */
1420 cfg
->param_area
= MAX (cfg
->param_area
, MIPS_STACK_PARAM_OFFSET
);
1422 header
= cfg
->header
;
1424 if (cfg
->arch
.omit_fp
)
1425 frame_reg
= mips_sp
;
1427 frame_reg
= mips_fp
;
1428 cfg
->frame_reg
= frame_reg
;
1429 if (frame_reg
!= mips_sp
) {
1430 cfg
->used_int_regs
|= 1 << frame_reg
;
1435 if (!MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1436 /* FIXME: handle long and FP values */
1437 switch (mini_get_underlying_type (sig
->ret
)->type
) {
1438 case MONO_TYPE_VOID
:
1442 cfg
->ret
->opcode
= OP_REGVAR
;
1443 cfg
->ret
->inst_c0
= cfg
->ret
->dreg
= mips_f0
;
1446 cfg
->ret
->opcode
= OP_REGVAR
;
1447 cfg
->ret
->inst_c0
= mips_v0
;
1451 /* Space for outgoing parameters, including a0-a3 */
1452 offset
+= cfg
->param_area
;
1454 /* Now handle the local variables */
1456 curinst
= cfg
->locals_start
;
1457 for (i
= curinst
; i
< cfg
->num_varinfo
; ++i
) {
1458 inst
= cfg
->varinfo
[i
];
1459 if ((inst
->flags
& MONO_INST_IS_DEAD
) || inst
->opcode
== OP_REGVAR
)
1462 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1463 * pinvoke wrappers when they call functions returning structure
1465 if (inst
->backend
.is_pinvoke
&& MONO_TYPE_ISSTRUCT (inst
->inst_vtype
) && inst
->inst_vtype
->type
!= MONO_TYPE_TYPEDBYREF
)
1466 size
= mono_class_native_size (mono_class_from_mono_type_internal (inst
->inst_vtype
), (unsigned int *) &align
);
1468 size
= mono_type_size (inst
->inst_vtype
, &align
);
1470 offset
+= align
- 1;
1471 offset
&= ~(align
- 1);
1472 inst
->inst_offset
= offset
;
1473 inst
->opcode
= OP_REGOFFSET
;
1474 inst
->inst_basereg
= frame_reg
;
1476 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1479 /* Space for LMF (if needed) */
1480 if (cfg
->method
->save_lmf
) {
1481 /* align the offset to 16 bytes */
1482 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1483 cfg
->arch
.lmf_offset
= offset
;
1484 offset
+= sizeof (MonoLMF
);
1487 if (sig
->call_convention
== MONO_CALL_VARARG
) {
1491 /* Allocate a local slot to hold the sig cookie address */
1492 offset
+= align
- 1;
1493 offset
&= ~(align
- 1);
1494 cfg
->sig_cookie
= offset
;
1498 offset
+= SIZEOF_REGISTER
- 1;
1499 offset
&= ~(SIZEOF_REGISTER
- 1);
1501 /* Space for saved registers */
1502 cfg
->arch
.iregs_offset
= offset
;
1503 iregs_to_save
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
1504 if (iregs_to_save
) {
1505 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
1506 if (iregs_to_save
& (1 << i
)) {
1507 offset
+= SIZEOF_REGISTER
;
1512 /* saved float registers */
1514 fregs_to_restore
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
1515 if (fregs_to_restore
) {
1516 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
1517 if (fregs_to_restore
& (1 << i
)) {
1518 offset
+= sizeof(double);
1524 #if _MIPS_SIM == _ABIO32
1525 /* Now add space for saving the ra */
1526 offset
+= TARGET_SIZEOF_VOID_P
;
1529 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1530 cfg
->stack_offset
= offset
;
1531 cfg
->arch
.local_alloc_offset
= cfg
->stack_offset
;
1535 * Now allocate stack slots for the int arg regs (a0 - a3)
1536 * On MIPS o32, these are just above the incoming stack pointer
1537 * Even if the arg has been assigned to a regvar, it gets a stack slot
1540 /* Return struct-by-value results in a hidden first argument */
1541 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1542 cfg
->vret_addr
->opcode
= OP_REGOFFSET
;
1543 cfg
->vret_addr
->inst_c0
= mips_a0
;
1544 cfg
->vret_addr
->inst_offset
= offset
;
1545 cfg
->vret_addr
->inst_basereg
= frame_reg
;
1546 offset
+= SIZEOF_REGISTER
;
1549 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
1550 inst
= cfg
->args
[i
];
1551 if (inst
->opcode
!= OP_REGVAR
) {
1554 if (sig
->hasthis
&& (i
== 0))
1555 arg_type
= mono_get_object_type ();
1557 arg_type
= sig
->params
[i
- sig
->hasthis
];
1559 inst
->opcode
= OP_REGOFFSET
;
1560 size
= mono_type_size (arg_type
, &align
);
1562 if (size
< SIZEOF_REGISTER
) {
1563 size
= SIZEOF_REGISTER
;
1564 align
= SIZEOF_REGISTER
;
1566 inst
->inst_basereg
= frame_reg
;
1567 offset
= (offset
+ align
- 1) & ~(align
- 1);
1568 inst
->inst_offset
= offset
;
1570 if (cfg
->verbose_level
> 1)
1571 printf ("allocating param %d to fp[%d]\n", i
, inst
->inst_offset
);
1574 #if _MIPS_SIM == _ABIO32
1575 /* o32: Even a0-a3 get stack slots */
1576 size
= SIZEOF_REGISTER
;
1577 align
= SIZEOF_REGISTER
;
1578 inst
->inst_basereg
= frame_reg
;
1579 offset
= (offset
+ align
- 1) & ~(align
- 1);
1580 inst
->inst_offset
= offset
;
1582 if (cfg
->verbose_level
> 1)
1583 printf ("allocating param %d to fp[%d]\n", i
, inst
->inst_offset
);
1587 #if _MIPS_SIM == _ABIN32
1588 /* Now add space for saving the ra */
1589 offset
+= TARGET_SIZEOF_VOID_P
;
1592 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1593 cfg
->stack_offset
= offset
;
1594 cfg
->arch
.local_alloc_offset
= cfg
->stack_offset
;
1599 mono_arch_create_vars (MonoCompile
*cfg
)
1601 MonoMethodSignature
*sig
;
1603 sig
= mono_method_signature_internal (cfg
->method
);
1605 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1606 cfg
->vret_addr
= mono_compile_create_var (cfg
, mono_get_int_type (), OP_ARG
);
1607 if (G_UNLIKELY (cfg
->verbose_level
> 1)) {
1608 printf ("vret_addr = ");
1609 mono_print_ins (cfg
->vret_addr
);
1614 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1615 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1619 * take the arguments and generate the arch-specific
1620 * instructions to properly call the function in call.
1621 * This includes pushing, moving arguments to the right register
1623 * Issue: who does the spilling if needed, and when?
1626 emit_sig_cookie (MonoCompile
*cfg
, MonoCallInst
*call
, CallInfo
*cinfo
)
1628 MonoMethodSignature
*tmp_sig
;
1631 if (MONO_IS_TAILCALL_OPCODE (call
))
1634 /* FIXME: Add support for signature tokens to AOT */
1635 cfg
->disable_aot
= TRUE
;
1638 * mono_ArgIterator_Setup assumes the signature cookie is
1639 * passed first and all the arguments which were before it are
1640 * passed on the stack after the signature. So compensate by
1641 * passing a different signature.
1643 tmp_sig
= mono_metadata_signature_dup (call
->signature
);
1644 tmp_sig
->param_count
-= call
->signature
->sentinelpos
;
1645 tmp_sig
->sentinelpos
= 0;
1646 memcpy (tmp_sig
->params
, call
->signature
->params
+ call
->signature
->sentinelpos
, tmp_sig
->param_count
* sizeof (MonoType
*));
1648 MONO_INST_NEW (cfg
, sig_arg
, OP_ICONST
);
1649 sig_arg
->dreg
= mono_alloc_ireg (cfg
);
1650 sig_arg
->inst_p0
= tmp_sig
;
1651 MONO_ADD_INS (cfg
->cbb
, sig_arg
);
1653 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_sp
, cinfo
->sig_cookie
.offset
, sig_arg
->dreg
);
1657 mono_arch_emit_call (MonoCompile
*cfg
, MonoCallInst
*call
)
1660 MonoMethodSignature
*sig
;
1665 sig
= call
->signature
;
1666 n
= sig
->param_count
+ sig
->hasthis
;
1668 cinfo
= get_call_info (cfg
->mempool
, sig
);
1669 if (cinfo
->struct_ret
)
1670 call
->used_iregs
|= 1 << cinfo
->struct_ret
;
1672 for (i
= 0; i
< n
; ++i
) {
1673 ArgInfo
*ainfo
= cinfo
->args
+ i
;
1676 if (i
>= sig
->hasthis
)
1677 t
= sig
->params
[i
- sig
->hasthis
];
1679 t
= mono_get_int_type ();
1680 t
= mini_get_underlying_type (t
);
1682 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1683 /* Emit the signature cookie just before the implicit arguments */
1684 emit_sig_cookie (cfg
, call
, cinfo
);
1687 if (is_virtual
&& i
== 0) {
1688 /* the argument will be attached to the call instrucion */
1689 in
= call
->args
[i
];
1690 call
->used_iregs
|= 1 << ainfo
->reg
;
1693 in
= call
->args
[i
];
1694 if (ainfo
->storage
== ArgInIReg
) {
1695 #if SIZEOF_REGISTER == 4
1696 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1697 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1698 ins
->dreg
= mono_alloc_ireg (cfg
);
1699 ins
->sreg1
= MONO_LVREG_LS (in
->dreg
);
1700 MONO_ADD_INS (cfg
->cbb
, ins
);
1701 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
+ ls_word_idx
, FALSE
);
1703 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1704 ins
->dreg
= mono_alloc_ireg (cfg
);
1705 ins
->sreg1
= MONO_LVREG_MS (in
->dreg
);
1706 MONO_ADD_INS (cfg
->cbb
, ins
);
1707 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
+ ms_word_idx
, FALSE
);
1710 if (!t
->byref
&& (t
->type
== MONO_TYPE_R4
)) {
1713 #if PROMOTE_R4_TO_R8
1714 /* ??? - convert to single first? */
1715 MONO_INST_NEW (cfg
, ins
, OP_MIPS_CVTSD
);
1716 ins
->dreg
= mono_alloc_freg (cfg
);
1717 ins
->sreg1
= in
->dreg
;
1718 MONO_ADD_INS (cfg
->cbb
, ins
);
1723 /* trying to load float value into int registers */
1724 MONO_INST_NEW (cfg
, ins
, OP_MIPS_MFC1S
);
1725 ins
->dreg
= mono_alloc_ireg (cfg
);
1727 MONO_ADD_INS (cfg
->cbb
, ins
);
1728 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1729 } else if (!t
->byref
&& (t
->type
== MONO_TYPE_R8
)) {
1730 /* trying to load float value into int registers */
1731 MONO_INST_NEW (cfg
, ins
, OP_MIPS_MFC1D
);
1732 ins
->dreg
= mono_alloc_ireg (cfg
);
1733 ins
->sreg1
= in
->dreg
;
1734 MONO_ADD_INS (cfg
->cbb
, ins
);
1735 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1737 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1738 ins
->dreg
= mono_alloc_ireg (cfg
);
1739 ins
->sreg1
= in
->dreg
;
1740 MONO_ADD_INS (cfg
->cbb
, ins
);
1741 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1743 } else if (ainfo
->storage
== ArgStructByAddr
) {
1744 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1745 ins
->opcode
= OP_OUTARG_VT
;
1746 ins
->sreg1
= in
->dreg
;
1747 ins
->klass
= in
->klass
;
1748 ins
->inst_p0
= call
;
1749 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1750 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1751 MONO_ADD_INS (cfg
->cbb
, ins
);
1752 } else if (ainfo
->storage
== ArgStructByVal
) {
1753 /* this is further handled in mono_arch_emit_outarg_vt () */
1754 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1755 ins
->opcode
= OP_OUTARG_VT
;
1756 ins
->sreg1
= in
->dreg
;
1757 ins
->klass
= in
->klass
;
1758 ins
->inst_p0
= call
;
1759 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1760 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1761 MONO_ADD_INS (cfg
->cbb
, ins
);
1762 } else if (ainfo
->storage
== ArgOnStack
) {
1763 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1764 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1765 } else if (!t
->byref
&& ((t
->type
== MONO_TYPE_R4
) || (t
->type
== MONO_TYPE_R8
))) {
1766 if (t
->type
== MONO_TYPE_R8
)
1767 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER8_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1769 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER4_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1771 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1773 } else if (ainfo
->storage
== ArgInFReg
) {
1774 if (t
->type
== MONO_TYPE_VALUETYPE
) {
1775 /* this is further handled in mono_arch_emit_outarg_vt () */
1776 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1777 ins
->opcode
= OP_OUTARG_VT
;
1778 ins
->sreg1
= in
->dreg
;
1779 ins
->klass
= in
->klass
;
1780 ins
->inst_p0
= call
;
1781 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1782 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1783 MONO_ADD_INS (cfg
->cbb
, ins
);
1785 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1787 int dreg
= mono_alloc_freg (cfg
);
1789 if (ainfo
->size
== 4) {
1790 MONO_EMIT_NEW_UNALU (cfg
, OP_MIPS_CVTSD
, dreg
, in
->dreg
);
1792 MONO_INST_NEW (cfg
, ins
, OP_FMOVE
);
1794 ins
->sreg1
= in
->dreg
;
1795 MONO_ADD_INS (cfg
->cbb
, ins
);
1798 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1799 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1802 g_assert_not_reached ();
1806 /* Handle the case where there are no implicit arguments */
1807 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (n
== sig
->sentinelpos
))
1808 emit_sig_cookie (cfg
, call
, cinfo
);
1810 if (cinfo
->struct_ret
) {
1813 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
1814 vtarg
->sreg1
= call
->vret_var
->dreg
;
1815 vtarg
->dreg
= mono_alloc_preg (cfg
);
1816 MONO_ADD_INS (cfg
->cbb
, vtarg
);
1818 mono_call_inst_add_outarg_reg (cfg
, call
, vtarg
->dreg
, cinfo
->struct_ret
, FALSE
);
1822 * Reverse the call->out_args list.
1825 MonoInst
*prev
= NULL
, *list
= call
->out_args
, *next
;
1832 call
->out_args
= prev
;
1835 call
->stack_usage
= cinfo
->stack_usage
;
1836 cfg
->param_area
= MAX (cfg
->param_area
, cinfo
->stack_usage
);
1837 #if _MIPS_SIM == _ABIO32
1838 /* a0-a3 always present */
1839 cfg
->param_area
= MAX (cfg
->param_area
, 4 * SIZEOF_REGISTER
);
1841 cfg
->param_area
= (cfg
->param_area
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1842 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
1844 * should set more info in call, such as the stack space
1845 * used by the args that needs to be added back to esp
1850 mono_arch_emit_outarg_vt (MonoCompile
*cfg
, MonoInst
*ins
, MonoInst
*src
)
1852 MonoCallInst
*call
= (MonoCallInst
*)ins
->inst_p0
;
1853 ArgInfo
*ainfo
= ins
->inst_p1
;
1854 int ovf_size
= ainfo
->vtsize
;
1855 int doffset
= ainfo
->offset
;
1856 int i
, soffset
, dreg
;
1858 if (ainfo
->storage
== ArgStructByVal
) {
1860 if (cfg
->verbose_level
> 0) {
1861 char* nm
= mono_method_full_name (cfg
->method
, TRUE
);
1862 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1863 nm
, doffset
, ainfo
->size
, ovf_size
);
1869 for (i
= 0; i
< ainfo
->size
; ++i
) {
1870 dreg
= mono_alloc_ireg (cfg
);
1871 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, dreg
, src
->dreg
, soffset
);
1872 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
+ i
, FALSE
);
1873 soffset
+= SIZEOF_REGISTER
;
1875 if (ovf_size
!= 0) {
1876 mini_emit_memcpy (cfg
, mips_sp
, doffset
, src
->dreg
, soffset
, ovf_size
* sizeof (target_mgreg_t
), TARGET_SIZEOF_VOID_P
);
1878 } else if (ainfo
->storage
== ArgInFReg
) {
1879 int tmpr
= mono_alloc_freg (cfg
);
1881 if (ainfo
->size
== 4)
1882 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR4_MEMBASE
, tmpr
, src
->dreg
, 0);
1884 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR8_MEMBASE
, tmpr
, src
->dreg
, 0);
1885 dreg
= mono_alloc_freg (cfg
);
1886 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, dreg
, tmpr
);
1887 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1889 MonoInst
*vtcopy
= mono_compile_create_var (cfg
, m_class_get_byval_arg (src
->klass
), OP_LOCAL
);
1893 /* FIXME: alignment? */
1894 if (call
->signature
->pinvoke
) {
1895 size
= mono_type_native_stack_size (m_class_get_byval_arg (src
->klass
), NULL
);
1896 vtcopy
->backend
.is_pinvoke
= 1;
1898 size
= mini_type_stack_size (m_class_get_byval_arg (src
->klass
), NULL
);
1901 g_assert (ovf_size
> 0);
1903 EMIT_NEW_VARLOADA (cfg
, load
, vtcopy
, vtcopy
->inst_vtype
);
1904 mini_emit_memcpy (cfg
, load
->dreg
, 0, src
->dreg
, 0, size
, TARGET_SIZEOF_VOID_P
);
1907 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_at
, ainfo
->offset
, load
->dreg
);
1909 mono_call_inst_add_outarg_reg (cfg
, call
, load
->dreg
, ainfo
->reg
, FALSE
);
1914 mono_arch_emit_setret (MonoCompile
*cfg
, MonoMethod
*method
, MonoInst
*val
)
1916 MonoType
*ret
= mini_get_underlying_type (mono_method_signature_internal (method
)->ret
);
1919 #if (SIZEOF_REGISTER == 4)
1920 if (ret
->type
== MONO_TYPE_I8
|| ret
->type
== MONO_TYPE_U8
) {
1923 MONO_INST_NEW (cfg
, ins
, OP_SETLRET
);
1924 ins
->sreg1
= MONO_LVREG_LS (val
->dreg
);
1925 ins
->sreg2
= MONO_LVREG_MS (val
->dreg
);
1926 MONO_ADD_INS (cfg
->cbb
, ins
);
1930 if (ret
->type
== MONO_TYPE_R8
) {
1931 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, cfg
->ret
->dreg
, val
->dreg
);
1934 if (ret
->type
== MONO_TYPE_R4
) {
1935 MONO_EMIT_NEW_UNALU (cfg
, OP_MIPS_CVTSD
, cfg
->ret
->dreg
, val
->dreg
);
1939 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, cfg
->ret
->dreg
, val
->dreg
);
1943 mono_arch_peephole_pass_1 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1945 MonoInst
*ins
, *n
, *last_ins
= NULL
;
1947 if (cfg
->verbose_level
> 2)
1948 g_print ("Basic block %d peephole pass 1\n", bb
->block_num
);
1951 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
1952 if (cfg
->verbose_level
> 2)
1953 mono_print_ins_index (0, ins
);
1955 switch (ins
->opcode
) {
1957 case OP_LOAD_MEMBASE
:
1958 case OP_LOADI4_MEMBASE
:
1960 * OP_IADD reg2, reg1, const1
1961 * OP_LOAD_MEMBASE const2(reg2), reg3
1963 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1965 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
)){
1966 int const1
= last_ins
->inst_imm
;
1967 int const2
= ins
->inst_offset
;
1969 if (mips_is_imm16 (const1
+ const2
)) {
1970 ins
->inst_basereg
= last_ins
->sreg1
;
1971 ins
->inst_offset
= const1
+ const2
;
1981 bb
->last_ins
= last_ins
;
1985 mono_arch_peephole_pass_2 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1987 MonoInst
*ins
, *n
, *last_ins
= NULL
;
1990 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
1991 MonoInst
*last_ins
= ins
->prev
;
1993 switch (ins
->opcode
) {
1995 /* remove unnecessary multiplication with 1 */
1996 if (ins
->inst_imm
== 1) {
1997 if (ins
->dreg
!= ins
->sreg1
) {
1998 ins
->opcode
= OP_MOVE
;
2000 MONO_DELETE_INS (bb
, ins
);
2004 int power2
= mono_is_power_of_two (ins
->inst_imm
);
2006 ins
->opcode
= OP_SHL_IMM
;
2007 ins
->inst_imm
= power2
;
2011 case OP_LOAD_MEMBASE
:
2012 case OP_LOADI4_MEMBASE
:
2014 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2015 * OP_LOAD_MEMBASE offset(basereg), reg
2017 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_REG
2018 || last_ins
->opcode
== OP_STORE_MEMBASE_REG
) &&
2019 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2020 ins
->inst_offset
== last_ins
->inst_offset
) {
2021 if (ins
->dreg
== last_ins
->sreg1
) {
2022 MONO_DELETE_INS (bb
, ins
);
2025 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2026 ins
->opcode
= OP_MOVE
;
2027 ins
->sreg1
= last_ins
->sreg1
;
2032 * Note: reg1 must be different from the basereg in the second load
2033 * OP_LOAD_MEMBASE offset(basereg), reg1
2034 * OP_LOAD_MEMBASE offset(basereg), reg2
2036 * OP_LOAD_MEMBASE offset(basereg), reg1
2037 * OP_MOVE reg1, reg2
2039 if (last_ins
&& (last_ins
->opcode
== OP_LOADI4_MEMBASE
2040 || last_ins
->opcode
== OP_LOAD_MEMBASE
) &&
2041 ins
->inst_basereg
!= last_ins
->dreg
&&
2042 ins
->inst_basereg
== last_ins
->inst_basereg
&&
2043 ins
->inst_offset
== last_ins
->inst_offset
) {
2045 if (ins
->dreg
== last_ins
->dreg
) {
2046 MONO_DELETE_INS (bb
, ins
);
2049 ins
->opcode
= OP_MOVE
;
2050 ins
->sreg1
= last_ins
->dreg
;
2053 //g_assert_not_reached ();
2058 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2059 * OP_LOAD_MEMBASE offset(basereg), reg
2061 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2062 * OP_ICONST reg, imm
2064 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_IMM
2065 || last_ins
->opcode
== OP_STORE_MEMBASE_IMM
) &&
2066 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2067 ins
->inst_offset
== last_ins
->inst_offset
) {
2068 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2069 ins
->opcode
= OP_ICONST
;
2070 ins
->inst_c0
= last_ins
->inst_imm
;
2071 g_assert_not_reached (); // check this rule
2076 case OP_LOADU1_MEMBASE
:
2077 case OP_LOADI1_MEMBASE
:
2078 if (last_ins
&& (last_ins
->opcode
== OP_STOREI1_MEMBASE_REG
) &&
2079 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2080 ins
->inst_offset
== last_ins
->inst_offset
) {
2081 ins
->opcode
= (ins
->opcode
== OP_LOADI1_MEMBASE
) ? OP_ICONV_TO_I1
: OP_ICONV_TO_U1
;
2082 ins
->sreg1
= last_ins
->sreg1
;
2085 case OP_LOADU2_MEMBASE
:
2086 case OP_LOADI2_MEMBASE
:
2087 if (last_ins
&& (last_ins
->opcode
== OP_STOREI2_MEMBASE_REG
) &&
2088 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2089 ins
->inst_offset
== last_ins
->inst_offset
) {
2090 ins
->opcode
= (ins
->opcode
== OP_LOADI2_MEMBASE
) ? OP_ICONV_TO_I2
: OP_ICONV_TO_U2
;
2091 ins
->sreg1
= last_ins
->sreg1
;
2094 case OP_ICONV_TO_I4
:
2095 case OP_ICONV_TO_U4
:
2097 ins
->opcode
= OP_MOVE
;
2101 if (ins
->dreg
== ins
->sreg1
) {
2102 MONO_DELETE_INS (bb
, ins
);
2106 * OP_MOVE sreg, dreg
2107 * OP_MOVE dreg, sreg
2109 if (last_ins
&& last_ins
->opcode
== OP_MOVE
&&
2110 ins
->sreg1
== last_ins
->dreg
&&
2111 ins
->dreg
== last_ins
->sreg1
) {
2112 MONO_DELETE_INS (bb
, ins
);
2120 bb
->last_ins
= last_ins
;
2124 mono_arch_decompose_long_opts (MonoCompile
*cfg
, MonoInst
*ins
)
2132 switch (ins
->opcode
) {
2134 tmp1
= mono_alloc_ireg (cfg
);
2135 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2136 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
2137 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2138 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2143 tmp1
= mono_alloc_ireg (cfg
);
2144 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, ins
->dreg
+1, ins
->sreg1
+1, ins_get_l_low (ins
));
2145 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
2146 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, ins
->dreg
+2, ins
->sreg1
+2, ins_get_l_high (ins
));
2147 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2152 tmp1
= mono_alloc_ireg (cfg
);
2153 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2154 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
2155 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2156 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2161 tmp1
= mono_alloc_ireg (cfg
);
2162 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, ins
->dreg
+1, ins
->sreg1
+1, ins_get_l_low (ins
));
2163 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
2164 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, ins
->dreg
+2, ins
->sreg1
+2, ins_get_l_high (ins
));
2165 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2170 tmp1
= mono_alloc_ireg (cfg
);
2171 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, mips_zero
, ins
->sreg1
+1);
2172 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, mips_zero
, ins
->dreg
+1);
2173 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, mips_zero
, ins
->sreg1
+2);
2174 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2179 tmp1
= mono_alloc_ireg (cfg
);
2180 tmp2
= mono_alloc_ireg (cfg
);
2181 tmp3
= mono_alloc_ireg (cfg
);
2182 tmp4
= mono_alloc_ireg (cfg
);
2183 tmp5
= mono_alloc_ireg (cfg
);
2185 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2187 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2188 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp5
, ins
->dreg
+1, ins
->sreg1
+1);
2190 /* add the high 32-bits, and add in the carry from the low 32-bits */
2191 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2192 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, tmp5
, ins
->dreg
+2);
2194 /* Overflow happens if
2195 * neg + neg = pos or
2197 * XOR of the high bits returns 0 if the signs match
2198 * XOR of that with the high bit of the result return 1 if overflow.
2201 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2202 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
+2, ins
->sreg2
+2);
2204 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2205 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->dreg
+2, ins
->sreg2
+2);
2206 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tmp2
, tmp2
);
2208 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2209 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tmp3
, tmp2
, tmp1
);
2210 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp4
, tmp3
, 31);
2212 /* Now, if (tmp4 == 0) then overflow */
2213 MONO_EMIT_NEW_COMPARE_EXC (cfg
, EQ
, tmp4
, mips_zero
, "OverflowException");
2217 case OP_LADD_OVF_UN
:
2218 tmp1
= mono_alloc_ireg (cfg
);
2219 tmp2
= mono_alloc_ireg (cfg
);
2221 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2222 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
2223 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2224 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, tmp1
, ins
->dreg
+2);
2225 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp2
, ins
->dreg
+2, ins
->sreg1
+2);
2226 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp2
, mips_zero
, "OverflowException");
2231 tmp1
= mono_alloc_ireg (cfg
);
2232 tmp2
= mono_alloc_ireg (cfg
);
2233 tmp3
= mono_alloc_ireg (cfg
);
2234 tmp4
= mono_alloc_ireg (cfg
);
2235 tmp5
= mono_alloc_ireg (cfg
);
2237 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2239 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp5
, ins
->sreg1
+1, ins
->dreg
+1);
2240 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2241 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp5
);
2243 /* Overflow happens if
2244 * neg - pos = pos or
2246 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2248 * tmp1 = (lhs ^ rhs)
2249 * tmp2 = (lhs ^ result)
2250 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2253 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
+2, ins
->sreg2
+2);
2254 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->sreg1
+2, ins
->dreg
+2);
2255 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tmp3
, tmp2
, tmp1
);
2256 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp4
, tmp3
, 31);
2258 /* Now, if (tmp4 == 1) then overflow */
2259 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp4
, mips_zero
, "OverflowException");
2263 case OP_LSUB_OVF_UN
:
2264 tmp1
= mono_alloc_ireg (cfg
);
2265 tmp2
= mono_alloc_ireg (cfg
);
2267 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2268 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
2269 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2270 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2272 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp2
, ins
->sreg1
+2, ins
->dreg
+2);
2273 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp2
, mips_zero
, "OverflowException");
2276 case OP_LCONV_TO_OVF_I4_2
:
2277 tmp1
= mono_alloc_ireg (cfg
);
2279 /* Overflows if reg2 != sign extension of reg1 */
2280 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp1
, ins
->sreg1
, 31);
2281 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, ins
->sreg2
, tmp1
, "OverflowException");
2282 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
2291 mono_arch_decompose_opts (MonoCompile
*cfg
, MonoInst
*ins
)
2299 switch (ins
->opcode
) {
2301 tmp1
= mono_alloc_ireg (cfg
);
2302 tmp2
= mono_alloc_ireg (cfg
);
2303 tmp3
= mono_alloc_ireg (cfg
);
2304 tmp4
= mono_alloc_ireg (cfg
);
2305 tmp5
= mono_alloc_ireg (cfg
);
2307 /* add the operands */
2309 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2311 /* Overflow happens if
2312 * neg + neg = pos or
2315 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2316 * XOR of the high bit returns 0 if the signs match
2317 * XOR of that with the high bit of the result return 1 if overflow.
2320 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2321 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
, ins
->sreg2
);
2323 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2324 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->dreg
, ins
->sreg2
);
2325 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tmp3
, tmp2
);
2327 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2328 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tmp4
, tmp3
, tmp1
);
2330 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp5
, tmp4
, 31);
2332 /* Now, if (tmp5 == 0) then overflow */
2333 MONO_EMIT_NEW_COMPARE_EXC (cfg
, EQ
, tmp5
, mips_zero
, "OverflowException");
2334 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2335 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->dreg
);
2339 case OP_IADD_OVF_UN
:
2340 tmp1
= mono_alloc_ireg (cfg
);
2342 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2343 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
, ins
->sreg1
);
2344 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp1
, mips_zero
, "OverflowException");
2345 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2346 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->dreg
);
2351 tmp1
= mono_alloc_ireg (cfg
);
2352 tmp2
= mono_alloc_ireg (cfg
);
2353 tmp3
= mono_alloc_ireg (cfg
);
2354 tmp4
= mono_alloc_ireg (cfg
);
2355 tmp5
= mono_alloc_ireg (cfg
);
2357 /* add the operands */
2359 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2361 /* Overflow happens if
2362 * neg - pos = pos or
2364 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2366 * tmp1 = (lhs ^ rhs)
2367 * tmp2 = (lhs ^ result)
2368 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2371 /* tmp3 = 1 if the signs of the two inputs differ */
2372 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
, ins
->sreg2
);
2373 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->sreg1
, ins
->dreg
);
2374 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_MIPS_SLTI
, tmp3
, tmp1
, 0);
2375 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_MIPS_SLTI
, tmp4
, tmp2
, 0);
2376 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tmp5
, tmp4
, tmp3
);
2378 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp5
, mips_zero
, "OverflowException");
2379 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2380 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->dreg
);
2384 case OP_ISUB_OVF_UN
:
2385 tmp1
= mono_alloc_ireg (cfg
);
2387 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2388 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
, ins
->dreg
);
2389 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp1
, mips_zero
, "OverflowException");
2390 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2391 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->dreg
);
2398 map_to_reg_reg_op (int op
)
2407 case OP_COMPARE_IMM
:
2409 case OP_ICOMPARE_IMM
:
2411 case OP_LCOMPARE_IMM
:
2427 case OP_LOAD_MEMBASE
:
2428 return OP_LOAD_MEMINDEX
;
2429 case OP_LOADI4_MEMBASE
:
2430 return OP_LOADI4_MEMINDEX
;
2431 case OP_LOADU4_MEMBASE
:
2432 return OP_LOADU4_MEMINDEX
;
2433 case OP_LOADU1_MEMBASE
:
2434 return OP_LOADU1_MEMINDEX
;
2435 case OP_LOADI2_MEMBASE
:
2436 return OP_LOADI2_MEMINDEX
;
2437 case OP_LOADU2_MEMBASE
:
2438 return OP_LOADU2_MEMINDEX
;
2439 case OP_LOADI1_MEMBASE
:
2440 return OP_LOADI1_MEMINDEX
;
2441 case OP_LOADR4_MEMBASE
:
2442 return OP_LOADR4_MEMINDEX
;
2443 case OP_LOADR8_MEMBASE
:
2444 return OP_LOADR8_MEMINDEX
;
2445 case OP_STOREI1_MEMBASE_REG
:
2446 return OP_STOREI1_MEMINDEX
;
2447 case OP_STOREI2_MEMBASE_REG
:
2448 return OP_STOREI2_MEMINDEX
;
2449 case OP_STOREI4_MEMBASE_REG
:
2450 return OP_STOREI4_MEMINDEX
;
2451 case OP_STORE_MEMBASE_REG
:
2452 return OP_STORE_MEMINDEX
;
2453 case OP_STORER4_MEMBASE_REG
:
2454 return OP_STORER4_MEMINDEX
;
2455 case OP_STORER8_MEMBASE_REG
:
2456 return OP_STORER8_MEMINDEX
;
2457 case OP_STORE_MEMBASE_IMM
:
2458 return OP_STORE_MEMBASE_REG
;
2459 case OP_STOREI1_MEMBASE_IMM
:
2460 return OP_STOREI1_MEMBASE_REG
;
2461 case OP_STOREI2_MEMBASE_IMM
:
2462 return OP_STOREI2_MEMBASE_REG
;
2463 case OP_STOREI4_MEMBASE_IMM
:
2464 return OP_STOREI4_MEMBASE_REG
;
2465 case OP_STOREI8_MEMBASE_IMM
:
2466 return OP_STOREI8_MEMBASE_REG
;
2468 if (mono_op_imm_to_op (op
) == -1)
2469 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op
));
2470 return mono_op_imm_to_op (op
);
2474 map_to_mips_op (int op
)
2478 return OP_MIPS_FBEQ
;
2480 return OP_MIPS_FBGE
;
2482 return OP_MIPS_FBGT
;
2484 return OP_MIPS_FBLE
;
2486 return OP_MIPS_FBLT
;
2488 return OP_MIPS_FBNE
;
2490 return OP_MIPS_FBGE_UN
;
2492 return OP_MIPS_FBGT_UN
;
2494 return OP_MIPS_FBLE_UN
;
2496 return OP_MIPS_FBLT_UN
;
2504 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op
), __FUNCTION__
);
2505 g_assert_not_reached ();
2509 #define NEW_INS(cfg,after,dest,op) do { \
2510 MONO_INST_NEW((cfg), (dest), (op)); \
2511 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2514 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2516 MONO_INST_NEW(cfg, temp, (op)); \
2517 mono_bblock_insert_after_ins (bb, (pos), temp); \
2518 temp->dreg = (_dreg); \
2519 temp->sreg1 = (_sreg1); \
2520 temp->sreg2 = (_sreg2); \
2524 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2526 MONO_INST_NEW(cfg, temp, (op)); \
2527 mono_bblock_insert_after_ins (bb, (pos), temp); \
2528 temp->dreg = (_dreg); \
2529 temp->sreg1 = (_sreg1); \
2530 temp->inst_c0 = (_imm); \
2535 * Remove from the instruction list the instructions that can't be
2536 * represented with very simple instructions with no register
2540 mono_arch_lowering_pass (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2542 MonoInst
*ins
, *next
, *temp
, *last_ins
= NULL
;
2546 if (cfg
->verbose_level
> 2) {
2549 g_print ("BASIC BLOCK %d (before lowering)\n", bb
->block_num
);
2550 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2551 mono_print_ins_index (idx
++, ins
);
2557 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2559 switch (ins
->opcode
) {
2564 /* Branch opts can eliminate the branch */
2565 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2571 case OP_COMPARE_IMM
:
2572 case OP_ICOMPARE_IMM
:
2573 case OP_LCOMPARE_IMM
:
2575 /* Branch opts can eliminate the branch */
2576 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2580 if (ins
->inst_imm
) {
2581 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2582 temp
->inst_c0
= ins
->inst_imm
;
2583 temp
->dreg
= mono_alloc_ireg (cfg
);
2584 ins
->sreg2
= temp
->dreg
;
2588 ins
->sreg2
= mips_zero
;
2590 if (ins
->opcode
== OP_COMPARE_IMM
)
2591 ins
->opcode
= OP_COMPARE
;
2592 else if (ins
->opcode
== OP_ICOMPARE_IMM
)
2593 ins
->opcode
= OP_ICOMPARE
;
2594 else if (ins
->opcode
== OP_LCOMPARE_IMM
)
2595 ins
->opcode
= OP_LCOMPARE
;
2598 case OP_IDIV_UN_IMM
:
2601 case OP_IREM_UN_IMM
:
2602 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2603 temp
->inst_c0
= ins
->inst_imm
;
2604 temp
->dreg
= mono_alloc_ireg (cfg
);
2605 ins
->sreg2
= temp
->dreg
;
2606 if (ins
->opcode
== OP_IDIV_IMM
)
2607 ins
->opcode
= OP_IDIV
;
2608 else if (ins
->opcode
== OP_IREM_IMM
)
2609 ins
->opcode
= OP_IREM
;
2610 else if (ins
->opcode
== OP_IDIV_UN_IMM
)
2611 ins
->opcode
= OP_IDIV_UN
;
2612 else if (ins
->opcode
== OP_IREM_UN_IMM
)
2613 ins
->opcode
= OP_IREM_UN
;
2615 /* handle rem separately */
2622 if ((ins
->inst_imm
& 0xffff0000) && (ins
->inst_imm
& 0xffff)) {
2623 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2624 temp
->inst_c0
= ins
->inst_imm
;
2625 temp
->dreg
= mono_alloc_ireg (cfg
);
2626 ins
->sreg2
= temp
->dreg
;
2627 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2637 /* unsigned 16 bit immediate */
2638 if (ins
->inst_imm
& 0xffff0000) {
2639 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2640 temp
->inst_c0
= ins
->inst_imm
;
2641 temp
->dreg
= mono_alloc_ireg (cfg
);
2642 ins
->sreg2
= temp
->dreg
;
2643 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2650 /* signed 16 bit immediate */
2651 if (!mips_is_imm16 (ins
->inst_imm
)) {
2652 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2653 temp
->inst_c0
= ins
->inst_imm
;
2654 temp
->dreg
= mono_alloc_ireg (cfg
);
2655 ins
->sreg2
= temp
->dreg
;
2656 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2662 if (!mips_is_imm16 (-ins
->inst_imm
)) {
2663 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2664 temp
->inst_c0
= ins
->inst_imm
;
2665 temp
->dreg
= mono_alloc_ireg (cfg
);
2666 ins
->sreg2
= temp
->dreg
;
2667 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2673 if (ins
->inst_imm
== 1) {
2674 ins
->opcode
= OP_MOVE
;
2677 if (ins
->inst_imm
== 0) {
2678 ins
->opcode
= OP_ICONST
;
2682 imm
= mono_is_power_of_two (ins
->inst_imm
);
2684 ins
->opcode
= OP_SHL_IMM
;
2685 ins
->inst_imm
= imm
;
2688 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2689 temp
->inst_c0
= ins
->inst_imm
;
2690 temp
->dreg
= mono_alloc_ireg (cfg
);
2691 ins
->sreg2
= temp
->dreg
;
2692 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2695 case OP_LOCALLOC_IMM
:
2696 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2697 temp
->inst_c0
= ins
->inst_imm
;
2698 temp
->dreg
= mono_alloc_ireg (cfg
);
2699 ins
->sreg1
= temp
->dreg
;
2700 ins
->opcode
= OP_LOCALLOC
;
2703 case OP_LOADR4_MEMBASE
:
2704 case OP_STORER4_MEMBASE_REG
:
2705 /* we can do two things: load the immed in a register
2706 * and use an indexed load, or see if the immed can be
2707 * represented as an ad_imm + a load with a smaller offset
2708 * that fits. We just do the first for now, optimize later.
2710 if (mips_is_imm16 (ins
->inst_offset
))
2712 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2713 temp
->inst_c0
= ins
->inst_offset
;
2714 temp
->dreg
= mono_alloc_ireg (cfg
);
2715 ins
->sreg2
= temp
->dreg
;
2716 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2719 case OP_STORE_MEMBASE_IMM
:
2720 case OP_STOREI1_MEMBASE_IMM
:
2721 case OP_STOREI2_MEMBASE_IMM
:
2722 case OP_STOREI4_MEMBASE_IMM
:
2723 case OP_STOREI8_MEMBASE_IMM
:
2724 if (!ins
->inst_imm
) {
2725 ins
->sreg1
= mips_zero
;
2726 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2729 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2730 temp
->inst_c0
= ins
->inst_imm
;
2731 temp
->dreg
= mono_alloc_ireg (cfg
);
2732 ins
->sreg1
= temp
->dreg
;
2733 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2735 goto loop_start
; /* make it handle the possibly big ins->inst_offset */
2741 /* Branch opts can eliminate the branch */
2742 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2749 * remap compare/branch and compare/set
2750 * to MIPS specific opcodes.
2752 next
->opcode
= map_to_mips_op (next
->opcode
);
2753 next
->sreg1
= ins
->sreg1
;
2754 next
->sreg2
= ins
->sreg2
;
2761 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2762 temp
->inst_c0
= (guint32
)ins
->inst_p0
;
2763 temp
->dreg
= mono_alloc_ireg (cfg
);
2764 ins
->inst_basereg
= temp
->dreg
;
2765 ins
->inst_offset
= 0;
2766 ins
->opcode
= ins
->opcode
== OP_R4CONST
? OP_LOADR4_MEMBASE
: OP_LOADR8_MEMBASE
;
2768 /* make it handle the possibly big ins->inst_offset
2769 * later optimize to use lis + load_membase
2774 g_assert (ins_is_compare(last_ins
));
2775 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->sreg1
, last_ins
->sreg2
);
2776 NULLIFY_INS(last_ins
);
2780 g_assert (ins_is_compare(last_ins
));
2781 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->sreg1
, last_ins
->sreg2
);
2782 NULLIFY_INS(last_ins
);
2786 g_assert (ins_is_compare(last_ins
));
2787 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2788 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2789 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2793 g_assert (ins_is_compare(last_ins
));
2794 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2795 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2796 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2800 g_assert (ins_is_compare(last_ins
));
2801 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2802 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2803 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2807 g_assert (ins_is_compare(last_ins
));
2808 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2809 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2810 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2814 g_assert (ins_is_compare(last_ins
));
2815 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2816 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2817 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2821 g_assert (ins_is_compare(last_ins
));
2822 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2823 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2824 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2828 g_assert (ins_is_compare(last_ins
));
2829 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2830 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2831 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2835 g_assert (ins_is_compare(last_ins
));
2836 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2837 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2838 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2843 g_assert (ins_is_compare(last_ins
));
2844 last_ins
->opcode
= OP_IXOR
;
2845 last_ins
->dreg
= mono_alloc_ireg(cfg
);
2846 INS_REWRITE_IMM(ins
, OP_MIPS_SLTIU
, last_ins
->dreg
, 1);
2851 INS_REWRITE(ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2852 NULLIFY_INS(last_ins
);
2858 INS_REWRITE(ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2859 NULLIFY_INS(last_ins
);
2864 g_assert (ins_is_compare(last_ins
));
2865 INS_REWRITE(ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2866 MONO_DELETE_INS(bb
, last_ins
);
2871 g_assert (ins_is_compare(last_ins
));
2872 INS_REWRITE(ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2873 MONO_DELETE_INS(bb
, last_ins
);
2876 case OP_COND_EXC_EQ
:
2877 case OP_COND_EXC_IEQ
:
2878 g_assert (ins_is_compare(last_ins
));
2879 INS_REWRITE(ins
, OP_MIPS_COND_EXC_EQ
, last_ins
->sreg1
, last_ins
->sreg2
);
2880 MONO_DELETE_INS(bb
, last_ins
);
2883 case OP_COND_EXC_GE
:
2884 case OP_COND_EXC_IGE
:
2885 g_assert (ins_is_compare(last_ins
));
2886 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GE
, last_ins
->sreg1
, last_ins
->sreg2
);
2887 MONO_DELETE_INS(bb
, last_ins
);
2890 case OP_COND_EXC_GT
:
2891 case OP_COND_EXC_IGT
:
2892 g_assert (ins_is_compare(last_ins
));
2893 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GT
, last_ins
->sreg1
, last_ins
->sreg2
);
2894 MONO_DELETE_INS(bb
, last_ins
);
2897 case OP_COND_EXC_LE
:
2898 case OP_COND_EXC_ILE
:
2899 g_assert (ins_is_compare(last_ins
));
2900 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LE
, last_ins
->sreg1
, last_ins
->sreg2
);
2901 MONO_DELETE_INS(bb
, last_ins
);
2904 case OP_COND_EXC_LT
:
2905 case OP_COND_EXC_ILT
:
2906 g_assert (ins_is_compare(last_ins
));
2907 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LT
, last_ins
->sreg1
, last_ins
->sreg2
);
2908 MONO_DELETE_INS(bb
, last_ins
);
2911 case OP_COND_EXC_NE_UN
:
2912 case OP_COND_EXC_INE_UN
:
2913 g_assert (ins_is_compare(last_ins
));
2914 INS_REWRITE(ins
, OP_MIPS_COND_EXC_NE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2915 MONO_DELETE_INS(bb
, last_ins
);
2918 case OP_COND_EXC_GE_UN
:
2919 case OP_COND_EXC_IGE_UN
:
2920 g_assert (ins_is_compare(last_ins
));
2921 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2922 MONO_DELETE_INS(bb
, last_ins
);
2925 case OP_COND_EXC_GT_UN
:
2926 case OP_COND_EXC_IGT_UN
:
2927 g_assert (ins_is_compare(last_ins
));
2928 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GT_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2929 MONO_DELETE_INS(bb
, last_ins
);
2932 case OP_COND_EXC_LE_UN
:
2933 case OP_COND_EXC_ILE_UN
:
2934 g_assert (ins_is_compare(last_ins
));
2935 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2936 MONO_DELETE_INS(bb
, last_ins
);
2939 case OP_COND_EXC_LT_UN
:
2940 case OP_COND_EXC_ILT_UN
:
2941 g_assert (ins_is_compare(last_ins
));
2942 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LT_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2943 MONO_DELETE_INS(bb
, last_ins
);
2946 case OP_COND_EXC_OV
:
2947 case OP_COND_EXC_IOV
: {
2948 int tmp1
, tmp2
, tmp3
, tmp4
, tmp5
;
2949 MonoInst
*pos
= last_ins
;
2951 /* Overflow happens if
2952 * neg + neg = pos or
2955 * (bit31s of operands match) AND (bit31 of operand
2956 * != bit31 of result)
2957 * XOR of the high bit returns 0 if the signs match
2958 * XOR of that with the high bit of the result return 1
2961 g_assert (last_ins
->opcode
== OP_IADC
);
2963 tmp1
= mono_alloc_ireg (cfg
);
2964 tmp2
= mono_alloc_ireg (cfg
);
2965 tmp3
= mono_alloc_ireg (cfg
);
2966 tmp4
= mono_alloc_ireg (cfg
);
2967 tmp5
= mono_alloc_ireg (cfg
);
2969 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2970 INS (pos
, OP_IXOR
, tmp1
, last_ins
->sreg1
, last_ins
->sreg2
);
2972 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2973 INS (pos
, OP_IXOR
, tmp2
, last_ins
->dreg
, last_ins
->sreg2
);
2974 INS (pos
, OP_INOT
, tmp3
, tmp2
, -1);
2976 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2977 INS (pos
, OP_IOR
, tmp4
, tmp3
, tmp1
);
2978 INS_IMM (pos
, OP_SHR_IMM
, tmp5
, tmp4
, 31);
2980 /* Now, if (tmp5 == 0) then overflow */
2981 INS_REWRITE(ins
, OP_MIPS_COND_EXC_EQ
, tmp5
, mips_zero
);
2986 case OP_COND_EXC_NO
:
2987 case OP_COND_EXC_INO
:
2988 g_assert_not_reached ();
2992 case OP_COND_EXC_IC
:
2993 g_assert_not_reached ();
2996 case OP_COND_EXC_NC
:
2997 case OP_COND_EXC_INC
:
2998 g_assert_not_reached ();
3004 bb
->last_ins
= last_ins
;
3005 bb
->max_vreg
= cfg
->next_vreg
;
3008 if (cfg
->verbose_level
> 2) {
3011 g_print ("BASIC BLOCK %d (after lowering)\n", bb
->block_num
);
3012 MONO_BB_FOR_EACH_INS (bb
, ins
) {
3013 mono_print_ins_index (idx
++, ins
);
3022 emit_float_to_int (MonoCompile
*cfg
, guchar
*code
, int dreg
, int sreg
, int size
, gboolean is_signed
)
3024 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3026 mips_truncwd (code
, mips_ftemp
, sreg
);
3028 mips_cvtwd (code
, mips_ftemp
, sreg
);
3030 mips_mfc1 (code
, dreg
, mips_ftemp
);
3033 mips_andi (code
, dreg
, dreg
, 0xff);
3034 else if (size
== 2) {
3035 mips_sll (code
, dreg
, dreg
, 16);
3036 mips_srl (code
, dreg
, dreg
, 16);
3040 mips_sll (code
, dreg
, dreg
, 24);
3041 mips_sra (code
, dreg
, dreg
, 24);
3043 else if (size
== 2) {
3044 mips_sll (code
, dreg
, dreg
, 16);
3045 mips_sra (code
, dreg
, dreg
, 16);
3052 * emit_load_volatile_arguments:
3054 * Load volatile arguments from the stack to the original input registers.
3055 * Required before a tailcall.
3058 emit_load_volatile_arguments(MonoCompile
*cfg
, guint8
*code
)
3060 MonoMethod
*method
= cfg
->method
;
3061 MonoMethodSignature
*sig
;
3066 sig
= mono_method_signature_internal (method
);
3068 if (!cfg
->arch
.cinfo
)
3069 cfg
->arch
.cinfo
= get_call_info (cfg
->mempool
, sig
);
3070 cinfo
= cfg
->arch
.cinfo
;
3072 if (cinfo
->struct_ret
) {
3073 ArgInfo
*ainfo
= &cinfo
->ret
;
3074 inst
= cfg
->vret_addr
;
3075 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3078 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
3079 ArgInfo
*ainfo
= cinfo
->args
+ i
;
3080 inst
= cfg
->args
[i
];
3081 if (inst
->opcode
== OP_REGVAR
) {
3082 if (ainfo
->storage
== ArgInIReg
)
3083 MIPS_MOVE (code
, ainfo
->reg
, inst
->dreg
);
3084 else if (ainfo
->storage
== ArgInFReg
)
3085 g_assert_not_reached();
3086 else if (ainfo
->storage
== ArgOnStack
) {
3089 g_assert_not_reached ();
3091 if (ainfo
->storage
== ArgInIReg
) {
3092 g_assert (mips_is_imm16 (inst
->inst_offset
));
3093 switch (ainfo
->size
) {
3095 mips_lb (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3098 mips_lh (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3102 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3105 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+ ls_word_offset
);
3106 mips_lw (code
, ainfo
->reg
+ 1, inst
->inst_basereg
, inst
->inst_offset
+ ms_word_offset
);
3109 g_assert_not_reached ();
3112 } else if (ainfo
->storage
== ArgOnStack
) {
3114 } else if (ainfo
->storage
== ArgInFReg
) {
3115 g_assert (mips_is_imm16 (inst
->inst_offset
));
3116 if (ainfo
->size
== 8) {
3117 #if _MIPS_SIM == _ABIO32
3118 mips_lwc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+ ls_word_offset
);
3119 mips_lwc1 (code
, ainfo
->reg
+1, inst
->inst_basereg
, inst
->inst_offset
+ ms_word_offset
);
3120 #elif _MIPS_SIM == _ABIN32
3121 mips_ldc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3124 else if (ainfo
->size
== 4)
3125 mips_lwc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3127 g_assert_not_reached ();
3128 } else if (ainfo
->storage
== ArgStructByVal
) {
3130 int doffset
= inst
->inst_offset
;
3132 g_assert (mips_is_imm16 (inst
->inst_offset
));
3133 g_assert (mips_is_imm16 (inst
->inst_offset
+ ainfo
->size
* sizeof (target_mgreg_t
)));
3134 for (i
= 0; i
< ainfo
->size
; ++i
) {
3135 mips_lw (code
, ainfo
->reg
+ i
, inst
->inst_basereg
, doffset
);
3136 doffset
+= SIZEOF_REGISTER
;
3138 } else if (ainfo
->storage
== ArgStructByAddr
) {
3139 g_assert (mips_is_imm16 (inst
->inst_offset
));
3140 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3142 g_assert_not_reached ();
3150 emit_reserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3152 int size
= cfg
->param_area
;
3154 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3155 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3160 ppc_lwz (code
, ppc_r0
, 0, ppc_sp
);
3161 if (ppc_is_imm16 (-size
)) {
3162 ppc_stwu (code
, ppc_r0
, -size
, ppc_sp
);
3164 ppc_load (code
, ppc_r12
, -size
);
3165 ppc_stwux (code
, ppc_r0
, ppc_sp
, ppc_r12
);
3172 emit_unreserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3174 int size
= cfg
->param_area
;
3176 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3177 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3182 ppc_lwz (code
, ppc_r0
, 0, ppc_sp
);
3183 if (ppc_is_imm16 (size
)) {
3184 ppc_stwu (code
, ppc_r0
, size
, ppc_sp
);
3186 ppc_load (code
, ppc_r12
, size
);
3187 ppc_stwux (code
, ppc_r0
, ppc_sp
, ppc_r12
);
3194 mono_arch_output_basic_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
3198 guint8
*code
= cfg
->native_code
+ cfg
->code_len
;
3199 MonoInst
*last_ins
= NULL
;
3203 /* we don't align basic blocks of loops on mips */
3205 if (cfg
->verbose_level
> 2)
3206 g_print ("Basic block %d starting at offset 0x%x\n", bb
->block_num
, bb
->native_offset
);
3208 cpos
= bb
->max_offset
;
3210 MONO_BB_FOR_EACH_INS (bb
, ins
) {
3211 const guint offset
= code
- cfg
->native_code
;
3212 set_code_cursor (cfg
, code
);
3213 max_len
= ins_get_size (ins
->opcode
);
3214 code
= realloc_code (cfg
, max_len
);
3216 mono_debug_record_line_number (cfg
, ins
, offset
);
3217 if (cfg
->verbose_level
> 2) {
3218 g_print (" @ 0x%x\t", offset
);
3219 mono_print_ins_index (ins_cnt
++, ins
);
3221 /* Check for virtual regs that snuck by */
3222 g_assert ((ins
->dreg
>= -1) && (ins
->dreg
< 32));
3224 switch (ins
->opcode
) {
3225 case OP_RELAXED_NOP
:
3228 case OP_DUMMY_ICONST
:
3229 case OP_DUMMY_I8CONST
:
3230 case OP_DUMMY_R8CONST
:
3231 case OP_DUMMY_R4CONST
:
3232 case OP_NOT_REACHED
:
3235 case OP_IL_SEQ_POINT
:
3236 mono_add_seq_point (cfg
, bb
, ins
, code
- cfg
->native_code
);
3238 case OP_SEQ_POINT
: {
3239 if (ins
->flags
& MONO_INST_SINGLE_STEP_LOC
) {
3240 guint32 addr
= (guint32
)ss_trigger_page
;
3242 mips_load_const (code
, mips_t9
, addr
);
3243 mips_lw (code
, mips_t9
, mips_t9
, 0);
3246 mono_add_seq_point (cfg
, bb
, ins
, code
- cfg
->native_code
);
3249 * A placeholder for a possible breakpoint inserted by
3250 * mono_arch_set_breakpoint ().
3252 /* mips_load_const () + mips_lw */
3259 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3260 mips_mflo (code
, ins
->dreg
);
3261 mips_mfhi (code
, ins
->dreg
+1);
3264 mips_multu (code
, ins
->sreg1
, ins
->sreg2
);
3265 mips_mflo (code
, ins
->dreg
);
3266 mips_mfhi (code
, ins
->dreg
+1);
3268 case OP_MEMORY_BARRIER
:
3269 mips_sync (code
, 0);
3271 case OP_STOREI1_MEMBASE_IMM
:
3272 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3273 if (mips_is_imm16 (ins
->inst_offset
)) {
3274 mips_sb (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3276 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3277 mips_sb (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3280 case OP_STOREI2_MEMBASE_IMM
:
3281 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3282 if (mips_is_imm16 (ins
->inst_offset
)) {
3283 mips_sh (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3285 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3286 mips_sh (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3289 case OP_STOREI8_MEMBASE_IMM
:
3290 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3291 if (mips_is_imm16 (ins
->inst_offset
)) {
3292 mips_sd (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3294 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3295 mips_sd (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3298 case OP_STORE_MEMBASE_IMM
:
3299 case OP_STOREI4_MEMBASE_IMM
:
3300 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3301 if (mips_is_imm16 (ins
->inst_offset
)) {
3302 mips_sw (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3304 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3305 mips_sw (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3308 case OP_STOREI1_MEMBASE_REG
:
3309 if (mips_is_imm16 (ins
->inst_offset
)) {
3310 mips_sb (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3312 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3313 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3314 mips_sb (code
, ins
->sreg1
, mips_at
, 0);
3317 case OP_STOREI2_MEMBASE_REG
:
3318 if (mips_is_imm16 (ins
->inst_offset
)) {
3319 mips_sh (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3321 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3322 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3323 mips_sh (code
, ins
->sreg1
, mips_at
, 0);
3326 case OP_STORE_MEMBASE_REG
:
3327 case OP_STOREI4_MEMBASE_REG
:
3328 if (mips_is_imm16 (ins
->inst_offset
)) {
3329 mips_sw (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3331 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3332 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3333 mips_sw (code
, ins
->sreg1
, mips_at
, 0);
3336 case OP_STOREI8_MEMBASE_REG
:
3337 if (mips_is_imm16 (ins
->inst_offset
)) {
3338 mips_sd (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3340 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3341 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3342 mips_sd (code
, ins
->sreg1
, mips_at
, 0);
3346 g_assert_not_reached ();
3347 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3348 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3350 case OP_LOADI8_MEMBASE
:
3351 if (mips_is_imm16 (ins
->inst_offset
)) {
3352 mips_ld (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3354 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3355 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3356 mips_ld (code
, ins
->dreg
, mips_at
, 0);
3359 case OP_LOAD_MEMBASE
:
3360 case OP_LOADI4_MEMBASE
:
3361 case OP_LOADU4_MEMBASE
:
3362 g_assert (ins
->dreg
!= -1);
3363 if (mips_is_imm16 (ins
->inst_offset
)) {
3364 mips_lw (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3366 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3367 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3368 mips_lw (code
, ins
->dreg
, mips_at
, 0);
3371 case OP_LOADI1_MEMBASE
:
3372 if (mips_is_imm16 (ins
->inst_offset
)) {
3373 mips_lb (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3375 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3376 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3377 mips_lb (code
, ins
->dreg
, mips_at
, 0);
3380 case OP_LOADU1_MEMBASE
:
3381 if (mips_is_imm16 (ins
->inst_offset
)) {
3382 mips_lbu (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3384 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3385 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3386 mips_lbu (code
, ins
->dreg
, mips_at
, 0);
3389 case OP_LOADI2_MEMBASE
:
3390 if (mips_is_imm16 (ins
->inst_offset
)) {
3391 mips_lh (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3393 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3394 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3395 mips_lh (code
, ins
->dreg
, mips_at
, 0);
3398 case OP_LOADU2_MEMBASE
:
3399 if (mips_is_imm16 (ins
->inst_offset
)) {
3400 mips_lhu (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3402 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3403 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3404 mips_lhu (code
, ins
->dreg
, mips_at
, 0);
3407 case OP_ICONV_TO_I1
:
3408 mips_sll (code
, mips_at
, ins
->sreg1
, 24);
3409 mips_sra (code
, ins
->dreg
, mips_at
, 24);
3411 case OP_ICONV_TO_I2
:
3412 mips_sll (code
, mips_at
, ins
->sreg1
, 16);
3413 mips_sra (code
, ins
->dreg
, mips_at
, 16);
3415 case OP_ICONV_TO_U1
:
3416 mips_andi (code
, ins
->dreg
, ins
->sreg1
, 0xff);
3418 case OP_ICONV_TO_U2
:
3419 mips_sll (code
, mips_at
, ins
->sreg1
, 16);
3420 mips_srl (code
, ins
->dreg
, mips_at
, 16);
3423 mips_slt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3426 g_assert (mips_is_imm16 (ins
->inst_imm
));
3427 mips_slti (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3430 mips_sltu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3433 g_assert (mips_is_imm16 (ins
->inst_imm
));
3434 mips_sltiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3438 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3439 * So instead of emitting a trap, we emit a call a C function and place a
3442 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_JIT_ICALL_ID
, GUINT_TO_POINTER (MONO_JIT_ICALL_mono_break
));
3443 mips_load (code
, mips_t9
, 0x1f1f1f1f);
3444 mips_jalr (code
, mips_t9
, mips_ra
);
3448 mips_addu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3451 mips_daddu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3456 g_assert (mips_is_imm16 (ins
->inst_imm
));
3457 mips_addiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3460 g_assert (mips_is_imm16 (ins
->inst_imm
));
3461 mips_daddiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3465 mips_subu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3468 mips_dsubu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3473 // we add the negated value
3474 g_assert (mips_is_imm16 (-ins
->inst_imm
));
3475 mips_addiu (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
3479 // we add the negated value
3480 g_assert (mips_is_imm16 (-ins
->inst_imm
));
3481 mips_daddiu (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
3486 mips_and (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3492 g_assert (!(ins
->inst_imm
& 0xffff0000));
3493 mips_andi (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3498 guint32
*divisor_is_m1
;
3499 guint32
*dividend_is_minvalue
;
3500 guint32
*divisor_is_zero
;
3502 mips_load_const (code
, mips_at
, -1);
3503 divisor_is_m1
= (guint32
*)(void *)code
;
3504 mips_bne (code
, ins
->sreg2
, mips_at
, 0);
3505 mips_lui (code
, mips_at
, mips_zero
, 0x8000);
3506 dividend_is_minvalue
= (guint32
*)(void *)code
;
3507 mips_bne (code
, ins
->sreg1
, mips_at
, 0);
3510 /* Divide Int32.MinValue by -1 -- throw exception */
3511 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3513 mips_patch (divisor_is_m1
, (guint32
)code
);
3514 mips_patch (dividend_is_minvalue
, (guint32
)code
);
3516 /* Put divide in branch delay slot (NOT YET) */
3517 divisor_is_zero
= (guint32
*)(void *)code
;
3518 mips_bne (code
, ins
->sreg2
, mips_zero
, 0);
3521 /* Divide by zero -- throw exception */
3522 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3524 mips_patch (divisor_is_zero
, (guint32
)code
);
3525 mips_div (code
, ins
->sreg1
, ins
->sreg2
);
3526 if (ins
->opcode
== OP_IDIV
)
3527 mips_mflo (code
, ins
->dreg
);
3529 mips_mfhi (code
, ins
->dreg
);
3534 guint32
*divisor_is_zero
= (guint32
*)(void *)code
;
3536 /* Put divide in branch delay slot (NOT YET) */
3537 mips_bne (code
, ins
->sreg2
, mips_zero
, 0);
3540 /* Divide by zero -- throw exception */
3541 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3543 mips_patch (divisor_is_zero
, (guint32
)code
);
3544 mips_divu (code
, ins
->sreg1
, ins
->sreg2
);
3545 if (ins
->opcode
== OP_IDIV_UN
)
3546 mips_mflo (code
, ins
->dreg
);
3548 mips_mfhi (code
, ins
->dreg
);
3552 g_assert_not_reached ();
3554 ppc_load (code
, ppc_r12
, ins
->inst_imm
);
3555 ppc_divwod (code
, ins
->dreg
, ins
->sreg1
, ppc_r12
);
3556 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3557 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3558 /* FIXME: use OverflowException for 0x80000000/-1 */
3559 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
3561 g_assert_not_reached();
3564 g_assert_not_reached ();
3566 mips_or (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3570 g_assert (!(ins
->inst_imm
& 0xffff0000));
3571 mips_ori (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3574 mips_xor (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3578 /* unsigned 16-bit immediate */
3579 g_assert (!(ins
->inst_imm
& 0xffff0000));
3580 mips_xori (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3583 mips_sllv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3587 mips_sll (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3590 mips_srav (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3593 mips_dsrav (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3597 mips_sra (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3600 mips_dsra (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x3f);
3603 case OP_ISHR_UN_IMM
:
3604 mips_srl (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3606 case OP_LSHR_UN_IMM
:
3607 mips_dsrl (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x3f);
3610 mips_srlv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3613 mips_dsrlv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3617 mips_nor (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3620 mips_subu (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3623 mips_dsubu (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3627 mips_mul (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3629 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3630 mips_mflo (code
, ins
->dreg
);
3635 #if SIZEOF_REGISTER == 8
3637 mips_dmult (code
, ins
->sreg1
, ins
->sreg2
);
3638 mips_mflo (code
, ins
->dreg
);
3643 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3644 mips_mflo (code
, ins
->dreg
);
3645 mips_mfhi (code
, mips_at
);
3648 mips_sra (code
, mips_temp
, ins
->dreg
, 31);
3649 patch
= (guint32
*)(void *)code
;
3650 mips_beq (code
, mips_temp
, mips_at
, 0);
3652 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3653 mips_patch (patch
, (guint32
)code
);
3656 case OP_IMUL_OVF_UN
: {
3658 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3659 mips_mflo (code
, ins
->dreg
);
3660 mips_mfhi (code
, mips_at
);
3663 patch
= (guint32
*)(void *)code
;
3664 mips_beq (code
, mips_at
, mips_zero
, 0);
3666 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3667 mips_patch (patch
, (guint32
)code
);
3671 mips_load_const (code
, ins
->dreg
, ins
->inst_c0
);
3673 #if SIZEOF_REGISTER == 8
3675 mips_load_const (code
, ins
->dreg
, ins
->inst_c0
);
3679 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_i1
, ins
->inst_p0
);
3680 mips_load (code
, ins
->dreg
, 0);
3684 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3686 case OP_MIPS_MTC1S_2
:
3687 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3688 mips_mtc1 (code
, ins
->dreg
+1, ins
->sreg2
);
3691 mips_mfc1 (code
, ins
->dreg
, ins
->sreg1
);
3694 mips_dmtc1 (code
, ins
->dreg
, ins
->sreg1
);
3698 mips_dmfc1 (code
, ins
->dreg
, ins
->sreg1
);
3700 mips_mfc1 (code
, ins
->dreg
, ins
->sreg1
+ ls_word_idx
);
3701 mips_mfc1 (code
, ins
->dreg
+1, ins
->sreg1
+ ms_word_idx
);
3705 case OP_ICONV_TO_I4
:
3706 case OP_ICONV_TO_U4
:
3708 if (ins
->dreg
!= ins
->sreg1
)
3709 MIPS_MOVE (code
, ins
->dreg
, ins
->sreg1
);
3711 #if SIZEOF_REGISTER == 8
3713 mips_dsll (code
, ins
->dreg
, ins
->sreg1
, 32);
3714 mips_dsrl (code
, ins
->dreg
, ins
->dreg
, 32);
3717 mips_dsll (code
, ins
->dreg
, ins
->sreg1
, 32);
3718 mips_dsra (code
, ins
->dreg
, ins
->dreg
, 32);
3722 int lsreg
= mips_v0
+ ls_word_idx
;
3723 int msreg
= mips_v0
+ ms_word_idx
;
3725 /* Get sreg1 into lsreg, sreg2 into msreg */
3727 if (ins
->sreg1
== msreg
) {
3728 if (ins
->sreg1
!= mips_at
)
3729 MIPS_MOVE (code
, mips_at
, ins
->sreg1
);
3730 if (ins
->sreg2
!= msreg
)
3731 MIPS_MOVE (code
, msreg
, ins
->sreg2
);
3732 MIPS_MOVE (code
, lsreg
, mips_at
);
3735 if (ins
->sreg2
!= msreg
)
3736 MIPS_MOVE (code
, msreg
, ins
->sreg2
);
3737 if (ins
->sreg1
!= lsreg
)
3738 MIPS_MOVE (code
, lsreg
, ins
->sreg1
);
3743 if (ins
->dreg
!= ins
->sreg1
) {
3744 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
3747 case OP_MOVE_F_TO_I4
:
3748 mips_cvtsd (code
, mips_ftemp
, ins
->sreg1
);
3749 mips_mfc1 (code
, ins
->dreg
, mips_ftemp
);
3751 case OP_MOVE_I4_TO_F
:
3752 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3753 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
3756 /* Convert from double to float and leave it there */
3757 mips_cvtsd (code
, ins
->dreg
, ins
->sreg1
);
3759 case OP_FCONV_TO_R4
:
3761 mips_cvtsd (code
, ins
->dreg
, ins
->sreg1
);
3763 /* Just a move, no precision change */
3764 if (ins
->dreg
!= ins
->sreg1
) {
3765 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
3770 /* ensure ins->sreg1 is not NULL */
3771 mips_lw (code
, mips_zero
, ins
->sreg1
, 0);
3774 g_assert (mips_is_imm16 (cfg
->sig_cookie
));
3775 mips_lw (code
, mips_at
, cfg
->frame_reg
, cfg
->sig_cookie
);
3776 mips_sw (code
, mips_at
, ins
->sreg1
, 0);
3789 case OP_VOIDCALL_REG
:
3791 case OP_FCALL_MEMBASE
:
3792 case OP_LCALL_MEMBASE
:
3793 case OP_VCALL_MEMBASE
:
3794 case OP_VCALL2_MEMBASE
:
3795 case OP_VOIDCALL_MEMBASE
:
3796 case OP_CALL_MEMBASE
:
3797 call
= (MonoCallInst
*)ins
;
3798 switch (ins
->opcode
) {
3805 mono_call_add_patch_info (cfg
, call
, offset
);
3806 if (ins
->flags
& MONO_INST_HAS_METHOD
) {
3807 mips_load (code
, mips_t9
, call
->method
);
3810 mips_load (code
, mips_t9
, call
->fptr
);
3812 mips_jalr (code
, mips_t9
, mips_ra
);
3819 case OP_VOIDCALL_REG
:
3821 MIPS_MOVE (code
, mips_t9
, ins
->sreg1
);
3822 mips_jalr (code
, mips_t9
, mips_ra
);
3825 case OP_FCALL_MEMBASE
:
3826 case OP_LCALL_MEMBASE
:
3827 case OP_VCALL_MEMBASE
:
3828 case OP_VCALL2_MEMBASE
:
3829 case OP_VOIDCALL_MEMBASE
:
3830 case OP_CALL_MEMBASE
:
3831 mips_lw (code
, mips_t9
, ins
->sreg1
, ins
->inst_offset
);
3832 mips_jalr (code
, mips_t9
, mips_ra
);
3836 #if PROMOTE_R4_TO_R8
3837 /* returned an FP R4 (single), promote to R8 (double) in place */
3838 switch (ins
->opcode
) {
3841 case OP_FCALL_MEMBASE
:
3842 if (call
->signature
->ret
->type
== MONO_TYPE_R4
)
3843 mips_cvtds (code
, mips_f0
, mips_f0
);
3851 int area_offset
= cfg
->param_area
;
3853 /* Round up ins->sreg1, mips_at ends up holding size */
3854 mips_addiu (code
, mips_at
, ins
->sreg1
, 31);
3855 mips_addiu (code
, mips_temp
, mips_zero
, ~31);
3856 mips_and (code
, mips_at
, mips_at
, mips_temp
);
3858 mips_subu (code
, mips_sp
, mips_sp
, mips_at
);
3859 g_assert (mips_is_imm16 (area_offset
));
3860 mips_addiu (code
, ins
->dreg
, mips_sp
, area_offset
);
3862 if (ins
->flags
& MONO_INST_INIT
) {
3865 buf
= (guint32
*)(void*)code
;
3866 mips_beq (code
, mips_at
, mips_zero
, 0);
3869 mips_move (code
, mips_temp
, ins
->dreg
);
3870 mips_sb (code
, mips_zero
, mips_temp
, 0);
3871 mips_addiu (code
, mips_at
, mips_at
, -1);
3872 mips_bne (code
, mips_at
, mips_zero
, -3);
3873 mips_addiu (code
, mips_temp
, mips_temp
, 1);
3875 mips_patch (buf
, (guint32
)code
);
3880 gpointer addr
= mono_arch_get_throw_exception(NULL
, FALSE
);
3881 mips_move (code
, mips_a0
, ins
->sreg1
);
3882 mips_call (code
, mips_t9
, addr
);
3883 mips_break (code
, 0xfc);
3887 gpointer addr
= mono_arch_get_rethrow_exception(NULL
, FALSE
);
3888 mips_move (code
, mips_a0
, ins
->sreg1
);
3889 mips_call (code
, mips_t9
, addr
);
3890 mips_break (code
, 0xfb);
3893 case OP_START_HANDLER
: {
3895 * The START_HANDLER instruction marks the beginning of
3896 * a handler block. It is called using a call
3897 * instruction, so mips_ra contains the return address.
3898 * Since the handler executes in the same stack frame
3899 * as the method itself, we can't use save/restore to
3900 * save the return address. Instead, we save it into
3901 * a dedicated variable.
3903 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3904 g_assert (spvar
->inst_basereg
!= mips_sp
);
3905 code
= emit_reserve_param_area (cfg
, code
);
3907 if (mips_is_imm16 (spvar
->inst_offset
)) {
3908 mips_sw (code
, mips_ra
, spvar
->inst_basereg
, spvar
->inst_offset
);
3910 mips_load_const (code
, mips_at
, spvar
->inst_offset
);
3911 mips_addu (code
, mips_at
, mips_at
, spvar
->inst_basereg
);
3912 mips_sw (code
, mips_ra
, mips_at
, 0);
3916 case OP_ENDFILTER
: {
3917 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3918 g_assert (spvar
->inst_basereg
!= mips_sp
);
3919 code
= emit_unreserve_param_area (cfg
, code
);
3921 if (ins
->sreg1
!= mips_v0
)
3922 MIPS_MOVE (code
, mips_v0
, ins
->sreg1
);
3923 if (mips_is_imm16 (spvar
->inst_offset
)) {
3924 mips_lw (code
, mips_ra
, spvar
->inst_basereg
, spvar
->inst_offset
);
3926 mips_load_const (code
, mips_at
, spvar
->inst_offset
);
3927 mips_addu (code
, mips_at
, mips_at
, spvar
->inst_basereg
);
3928 mips_lw (code
, mips_ra
, mips_at
, 0);
3930 mips_jr (code
, mips_ra
);
3934 case OP_ENDFINALLY
: {
3935 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3936 g_assert (spvar
->inst_basereg
!= mips_sp
);
3937 code
= emit_unreserve_param_area (cfg
, code
);
3938 mips_lw (code
, mips_t9
, spvar
->inst_basereg
, spvar
->inst_offset
);
3939 mips_jalr (code
, mips_t9
, mips_ra
);
3943 case OP_CALL_HANDLER
:
3944 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
3945 mips_lui (code
, mips_t9
, mips_zero
, 0);
3946 mips_addiu (code
, mips_t9
, mips_t9
, 0);
3947 mips_jalr (code
, mips_t9
, mips_ra
);
3949 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3950 for (GList
*tmp
= ins
->inst_eh_blocks
; tmp
!= bb
->clause_holes
; tmp
= tmp
->prev
)
3951 mono_cfg_add_try_hole (cfg
, ((MonoLeaveClause
*) tmp
->data
)->clause
, code
, bb
);
3954 ins
->inst_c0
= code
- cfg
->native_code
;
3957 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
3958 if (cfg
->arch
.long_branch
) {
3959 mips_lui (code
, mips_at
, mips_zero
, 0);
3960 mips_addiu (code
, mips_at
, mips_at
, 0);
3961 mips_jr (code
, mips_at
);
3965 mips_beq (code
, mips_zero
, mips_zero
, 0);
3970 mips_jr (code
, ins
->sreg1
);
3976 max_len
+= 4 * GPOINTER_TO_INT (ins
->klass
);
3977 code
= realloc_code (cfg
, max_len
);
3979 g_assert (ins
->sreg1
!= -1);
3980 mips_sll (code
, mips_at
, ins
->sreg1
, 2);
3981 if (1 || !(cfg
->flags
& MONO_CFG_HAS_CALLS
))
3982 MIPS_MOVE (code
, mips_t8
, mips_ra
);
3983 mips_bgezal (code
, mips_zero
, 1); /* bal */
3985 mips_addu (code
, mips_t9
, mips_ra
, mips_at
);
3986 /* Table is 16 or 20 bytes from target of bal above */
3987 if (1 || !(cfg
->flags
& MONO_CFG_HAS_CALLS
)) {
3988 MIPS_MOVE (code
, mips_ra
, mips_t8
);
3989 mips_lw (code
, mips_t9
, mips_t9
, 20);
3992 mips_lw (code
, mips_t9
, mips_t9
, 16);
3993 mips_jalr (code
, mips_t9
, mips_t8
);
3995 for (i
= 0; i
< GPOINTER_TO_INT (ins
->klass
); ++i
)
3996 mips_emit32 (code
, 0xfefefefe);
4001 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4002 mips_beq (code
, mips_at
, mips_zero
, 2);
4004 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4010 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4011 mips_bltz (code
, mips_at
, 2);
4013 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4019 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4020 mips_bgtz (code
, mips_at
, 2);
4022 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4025 case OP_MIPS_COND_EXC_EQ
:
4026 case OP_MIPS_COND_EXC_GE
:
4027 case OP_MIPS_COND_EXC_GT
:
4028 case OP_MIPS_COND_EXC_LE
:
4029 case OP_MIPS_COND_EXC_LT
:
4030 case OP_MIPS_COND_EXC_NE_UN
:
4031 case OP_MIPS_COND_EXC_GE_UN
:
4032 case OP_MIPS_COND_EXC_GT_UN
:
4033 case OP_MIPS_COND_EXC_LE_UN
:
4034 case OP_MIPS_COND_EXC_LT_UN
:
4036 case OP_MIPS_COND_EXC_OV
:
4037 case OP_MIPS_COND_EXC_NO
:
4038 case OP_MIPS_COND_EXC_C
:
4039 case OP_MIPS_COND_EXC_NC
:
4041 case OP_MIPS_COND_EXC_IEQ
:
4042 case OP_MIPS_COND_EXC_IGE
:
4043 case OP_MIPS_COND_EXC_IGT
:
4044 case OP_MIPS_COND_EXC_ILE
:
4045 case OP_MIPS_COND_EXC_ILT
:
4046 case OP_MIPS_COND_EXC_INE_UN
:
4047 case OP_MIPS_COND_EXC_IGE_UN
:
4048 case OP_MIPS_COND_EXC_IGT_UN
:
4049 case OP_MIPS_COND_EXC_ILE_UN
:
4050 case OP_MIPS_COND_EXC_ILT_UN
:
4052 case OP_MIPS_COND_EXC_IOV
:
4053 case OP_MIPS_COND_EXC_INO
:
4054 case OP_MIPS_COND_EXC_IC
:
4055 case OP_MIPS_COND_EXC_INC
: {
4059 /* If the condition is true, raise the exception */
4061 /* need to reverse test to skip around exception raising */
4063 /* For the moment, branch around a branch to avoid reversing
4066 /* Remember, an unpatched branch to 0 branches to the delay slot */
4067 switch (ins
->opcode
) {
4068 case OP_MIPS_COND_EXC_EQ
:
4069 throw = (guint32
*)(void *)code
;
4070 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, 0);
4074 case OP_MIPS_COND_EXC_NE_UN
:
4075 throw = (guint32
*)(void *)code
;
4076 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, 0);
4080 case OP_MIPS_COND_EXC_LE_UN
:
4081 mips_sltu (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
4082 throw = (guint32
*)(void *)code
;
4083 mips_beq (code
, mips_at
, mips_zero
, 0);
4087 case OP_MIPS_COND_EXC_GT
:
4088 mips_slt (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
4089 throw = (guint32
*)(void *)code
;
4090 mips_bne (code
, mips_at
, mips_zero
, 0);
4094 case OP_MIPS_COND_EXC_GT_UN
:
4095 mips_sltu (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
4096 throw = (guint32
*)(void *)code
;
4097 mips_bne (code
, mips_at
, mips_zero
, 0);
4101 case OP_MIPS_COND_EXC_LT
:
4102 mips_slt (code
, mips_at
, ins
->sreg1
, ins
->sreg2
);
4103 throw = (guint32
*)(void *)code
;
4104 mips_bne (code
, mips_at
, mips_zero
, 0);
4108 case OP_MIPS_COND_EXC_LT_UN
:
4109 mips_sltu (code
, mips_at
, ins
->sreg1
, ins
->sreg2
);
4110 throw = (guint32
*)(void *)code
;
4111 mips_bne (code
, mips_at
, mips_zero
, 0);
4116 /* Not yet implemented */
4117 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins
->opcode
));
4118 g_assert_not_reached ();
4120 skip
= (guint32
*)(void *)code
;
4121 mips_beq (code
, mips_zero
, mips_zero
, 0);
4123 mips_patch (throw, (guint32
)code
);
4124 code
= mips_emit_exc_by_name (code
, ins
->inst_p1
);
4125 mips_patch (skip
, (guint32
)code
);
4126 cfg
->bb_exit
->max_offset
+= 24;
4135 code
= mips_emit_cond_branch (cfg
, code
, ins
->opcode
, ins
);
4138 /* floating point opcodes */
4141 if (((guint32
)ins
->inst_p0
) & (1 << 15))
4142 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16)+1);
4144 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16));
4145 mips_ldc1 (code
, ins
->dreg
, mips_at
, ((guint32
)ins
->inst_p0
) & 0xffff);
4147 mips_load_const (code
, mips_at
, ins
->inst_p0
);
4148 mips_lwc1 (code
, ins
->dreg
, mips_at
, ls_word_offset
);
4149 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, ms_word_offset
);
4153 if (((guint32
)ins
->inst_p0
) & (1 << 15))
4154 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16)+1);
4156 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16));
4157 mips_lwc1 (code
, ins
->dreg
, mips_at
, ((guint32
)ins
->inst_p0
) & 0xffff);
4158 #if PROMOTE_R4_TO_R8
4159 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4162 case OP_STORER8_MEMBASE_REG
:
4163 if (mips_is_imm16 (ins
->inst_offset
)) {
4164 #if _MIPS_SIM == _ABIO32
4165 mips_swc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
+ ls_word_offset
);
4166 mips_swc1 (code
, ins
->sreg1
+1, ins
->inst_destbasereg
, ins
->inst_offset
+ ms_word_offset
);
4167 #elif _MIPS_SIM == _ABIN32
4168 mips_sdc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
4171 mips_load_const (code
, mips_at
, ins
->inst_offset
);
4172 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
4173 mips_swc1 (code
, ins
->sreg1
, mips_at
, ls_word_offset
);
4174 mips_swc1 (code
, ins
->sreg1
+1, mips_at
, ms_word_offset
);
4177 case OP_LOADR8_MEMBASE
:
4178 if (mips_is_imm16 (ins
->inst_offset
)) {
4179 #if _MIPS_SIM == _ABIO32
4180 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
+ ls_word_offset
);
4181 mips_lwc1 (code
, ins
->dreg
+1, ins
->inst_basereg
, ins
->inst_offset
+ ms_word_offset
);
4182 #elif _MIPS_SIM == _ABIN32
4183 mips_ldc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4186 mips_load_const (code
, mips_at
, ins
->inst_offset
);
4187 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
4188 mips_lwc1 (code
, ins
->dreg
, mips_at
, ls_word_offset
);
4189 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, ms_word_offset
);
4192 case OP_STORER4_MEMBASE_REG
:
4193 g_assert (mips_is_imm16 (ins
->inst_offset
));
4194 #if PROMOTE_R4_TO_R8
4195 /* Need to convert ins->sreg1 to single-precision first */
4196 mips_cvtsd (code
, mips_ftemp
, ins
->sreg1
);
4197 mips_swc1 (code
, mips_ftemp
, ins
->inst_destbasereg
, ins
->inst_offset
);
4199 mips_swc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
4203 g_assert (mips_is_imm16 (ins
->inst_offset
));
4204 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4206 case OP_LOADR4_MEMBASE
:
4207 g_assert (mips_is_imm16 (ins
->inst_offset
));
4208 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4209 #if PROMOTE_R4_TO_R8
4210 /* Convert to double precision in place */
4211 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4214 case OP_LOADR4_MEMINDEX
:
4215 mips_addu (code
, mips_at
, ins
->inst_basereg
, ins
->sreg2
);
4216 mips_lwc1 (code
, ins
->dreg
, mips_at
, 0);
4218 case OP_LOADR8_MEMINDEX
:
4219 mips_addu (code
, mips_at
, ins
->inst_basereg
, ins
->sreg2
);
4220 #if _MIPS_SIM == _ABIO32
4221 mips_lwc1 (code
, ins
->dreg
, mips_at
, ls_word_offset
);
4222 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, ms_word_offset
);
4223 #elif _MIPS_SIM == _ABIN32
4224 mips_ldc1 (code
, ins
->dreg
, mips_at
, 0);
4227 case OP_STORER4_MEMINDEX
:
4228 mips_addu (code
, mips_at
, ins
->inst_destbasereg
, ins
->sreg2
);
4229 #if PROMOTE_R4_TO_R8
4230 /* Need to convert ins->sreg1 to single-precision first */
4231 mips_cvtsd (code
, mips_ftemp
, ins
->sreg1
);
4232 mips_swc1 (code
, mips_ftemp
, mips_at
, 0);
4234 mips_swc1 (code
, ins
->sreg1
, mips_at
, 0);
4237 case OP_STORER8_MEMINDEX
:
4238 mips_addu (code
, mips_at
, ins
->inst_destbasereg
, ins
->sreg2
);
4239 #if _MIPS_SIM == _ABIO32
4240 mips_swc1 (code
, ins
->sreg1
, mips_at
, ls_word_offset
);
4241 mips_swc1 (code
, ins
->sreg1
+1, mips_at
, ms_word_offset
);
4242 #elif _MIPS_SIM == _ABIN32
4243 mips_sdc1 (code
, ins
->sreg1
, mips_at
, 0);
4246 case OP_ICONV_TO_R_UN
: {
4247 static const guint64 adjust_val
= 0x41F0000000000000ULL
;
4249 /* convert unsigned int to double */
4250 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4251 mips_bgez (code
, ins
->sreg1
, 5);
4252 mips_cvtdw (code
, ins
->dreg
, mips_ftemp
);
4254 mips_load (code
, mips_at
, (guint32
) &adjust_val
);
4255 mips_ldc1 (code
, mips_ftemp
, mips_at
, 0);
4256 mips_faddd (code
, ins
->dreg
, ins
->dreg
, mips_ftemp
);
4257 /* target is here */
4260 case OP_ICONV_TO_R4
:
4261 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4262 mips_cvtsw (code
, ins
->dreg
, mips_ftemp
);
4263 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4265 case OP_ICONV_TO_R8
:
4266 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4267 mips_cvtdw (code
, ins
->dreg
, mips_ftemp
);
4269 case OP_FCONV_TO_I1
:
4270 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, TRUE
);
4272 case OP_FCONV_TO_U1
:
4273 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, FALSE
);
4275 case OP_FCONV_TO_I2
:
4276 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, TRUE
);
4278 case OP_FCONV_TO_U2
:
4279 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, FALSE
);
4281 case OP_FCONV_TO_I4
:
4283 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, TRUE
);
4285 case OP_FCONV_TO_U4
:
4287 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, FALSE
);
4290 mips_fsqrtd (code
, ins
->dreg
, ins
->sreg1
);
4293 mips_faddd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4296 mips_fsubd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4299 mips_fmuld (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4302 mips_fdivd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4305 mips_fnegd (code
, ins
->dreg
, ins
->sreg1
);
4308 mips_fcmpd (code
, MIPS_FPU_EQ
, ins
->sreg1
, ins
->sreg2
);
4309 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4310 mips_fbtrue (code
, 2);
4312 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4315 mips_fcmpd (code
, MIPS_FPU_LT
, ins
->sreg1
, ins
->sreg2
);
4316 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4317 mips_fbtrue (code
, 2);
4319 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4322 /* Less than, or Unordered */
4323 mips_fcmpd (code
, MIPS_FPU_ULT
, ins
->sreg1
, ins
->sreg2
);
4324 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4325 mips_fbtrue (code
, 2);
4327 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4330 mips_fcmpd (code
, MIPS_FPU_ULE
, ins
->sreg1
, ins
->sreg2
);
4331 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4332 mips_fbtrue (code
, 2);
4334 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4337 /* Greater than, or Unordered */
4338 mips_fcmpd (code
, MIPS_FPU_OLE
, ins
->sreg1
, ins
->sreg2
);
4339 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4340 mips_fbtrue (code
, 2);
4342 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4347 case OP_MIPS_FBLT_UN
:
4349 case OP_MIPS_FBGT_UN
:
4351 case OP_MIPS_FBGE_UN
:
4353 case OP_MIPS_FBLE_UN
: {
4355 gboolean is_true
= TRUE
, is_ordered
= FALSE
;
4356 guint32
*buf
= NULL
;
4358 switch (ins
->opcode
) {
4372 case OP_MIPS_FBLT_UN
:
4373 cond
= MIPS_FPU_ULT
;
4381 case OP_MIPS_FBGT_UN
:
4382 cond
= MIPS_FPU_OLE
;
4390 case OP_MIPS_FBGE_UN
:
4391 cond
= MIPS_FPU_OLT
;
4395 cond
= MIPS_FPU_OLE
;
4399 case OP_MIPS_FBLE_UN
:
4400 cond
= MIPS_FPU_ULE
;
4404 g_assert_not_reached ();
4408 /* Skip the check if unordered */
4409 mips_fcmpd (code
, MIPS_FPU_UN
, ins
->sreg1
, ins
->sreg2
);
4411 buf
= (guint32
*)code
;
4412 mips_fbtrue (code
, 0);
4416 mips_fcmpd (code
, cond
, ins
->sreg1
, ins
->sreg2
);
4418 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4420 mips_fbtrue (code
, 0);
4422 mips_fbfalse (code
, 0);
4426 mips_patch (buf
, (guint32
)code
);
4430 guint32
*branch_patch
;
4432 mips_mfc1 (code
, mips_at
, ins
->sreg1
+1);
4433 mips_srl (code
, mips_at
, mips_at
, 16+4);
4434 mips_andi (code
, mips_at
, mips_at
, 2047);
4435 mips_addiu (code
, mips_at
, mips_at
, -2047);
4437 branch_patch
= (guint32
*)(void *)code
;
4438 mips_bne (code
, mips_at
, mips_zero
, 0);
4441 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4442 mips_patch (branch_patch
, (guint32
)code
);
4443 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
4447 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_c1
, ins
->inst_p0
);
4448 mips_load (code
, ins
->dreg
, 0x0f0f0f0f);
4450 case OP_LIVERANGE_START
: {
4451 if (cfg
->verbose_level
> 1)
4452 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg
, ins
->inst_c0
)->vreg
, (int)(code
- cfg
->native_code
));
4453 MONO_VARINFO (cfg
, ins
->inst_c0
)->live_range_start
= code
- cfg
->native_code
;
4456 case OP_LIVERANGE_END
: {
4457 if (cfg
->verbose_level
> 1)
4458 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg
, ins
->inst_c0
)->vreg
, (int)(code
- cfg
->native_code
));
4459 MONO_VARINFO (cfg
, ins
->inst_c0
)->live_range_end
= code
- cfg
->native_code
;
4462 case OP_GC_SAFE_POINT
:
4467 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins
->opcode
), __FUNCTION__
);
4468 g_assert_not_reached ();
4471 if ((cfg
->opt
& MONO_OPT_BRANCH
) && ((code
- cfg
->native_code
- offset
) > max_len
)) {
4472 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4473 mono_inst_name (ins
->opcode
), max_len
, code
- cfg
->native_code
- offset
);
4474 g_assert_not_reached ();
4482 set_code_cursor (cfg
, code
);
4486 mono_arch_register_lowlevel_calls (void)
4491 mono_arch_patch_code (MonoCompile
*cfg
, MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*ji
, gboolean run_cctors
, MonoError
*error
)
4493 MonoJumpInfo
*patch_info
;
4497 for (patch_info
= ji
; patch_info
; patch_info
= patch_info
->next
) {
4498 unsigned char *ip
= patch_info
->ip
.i
+ code
;
4499 const unsigned char *target
= NULL
;
4501 switch (patch_info
->type
) {
4502 case MONO_PATCH_INFO_IP
:
4503 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)ip
);
4505 case MONO_PATCH_INFO_SWITCH
: {
4506 gpointer
*table
= (gpointer
*)patch_info
->data
.table
->table
;
4509 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)table
);
4511 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
4512 table
[i
] = (int)patch_info
->data
.table
->table
[i
] + code
;
4516 case MONO_PATCH_INFO_METHODCONST
:
4517 case MONO_PATCH_INFO_CLASS
:
4518 case MONO_PATCH_INFO_IMAGE
:
4519 case MONO_PATCH_INFO_FIELD
:
4520 case MONO_PATCH_INFO_VTABLE
:
4521 case MONO_PATCH_INFO_IID
:
4522 case MONO_PATCH_INFO_SFLDA
:
4523 case MONO_PATCH_INFO_LDSTR
:
4524 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
4525 case MONO_PATCH_INFO_LDTOKEN
:
4526 case MONO_PATCH_INFO_R4
:
4527 case MONO_PATCH_INFO_R8
:
4528 /* from OP_AOTCONST : lui + addiu */
4529 target
= mono_resolve_patch_target (method
, domain
, code
, patch_info
, run_cctors
, error
);
4530 return_if_nok (error
);
4532 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)target
);
4535 case MONO_PATCH_INFO_EXC_NAME
:
4536 g_assert_not_reached ();
4537 *((gconstpointer
*)(void *)(ip
+ 1)) = patch_info
->data
.name
;
4540 case MONO_PATCH_INFO_NONE
:
4541 /* everything is dealt with at epilog output time */
4544 target
= mono_resolve_patch_target (method
, domain
, code
, patch_info
, run_cctors
, error
);
4545 return_if_nok (error
);
4547 mips_patch ((guint32
*)(void *)ip
, (guint32
)target
);
4554 mips_adjust_stackframe(MonoCompile
*cfg
)
4557 int delta
, threshold
, i
;
4558 MonoMethodSignature
*sig
;
4561 if (cfg
->stack_offset
== cfg
->arch
.local_alloc_offset
)
4564 /* adjust cfg->stack_offset for account for down-spilling */
4565 cfg
->stack_offset
+= SIZEOF_REGISTER
;
4567 /* re-align cfg->stack_offset if needed (due to var spilling) */
4568 cfg
->stack_offset
= (cfg
->stack_offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
4569 delta
= cfg
->stack_offset
- cfg
->arch
.local_alloc_offset
;
4570 if (cfg
->verbose_level
> 2) {
4571 g_print ("mips_adjust_stackframe:\n");
4572 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg
->arch
.local_alloc_offset
, cfg
->stack_offset
);
4574 threshold
= cfg
->arch
.local_alloc_offset
;
4575 ra_offset
= cfg
->stack_offset
- sizeof(gpointer
);
4576 if (cfg
->verbose_level
> 2) {
4577 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset
, ra_offset
, delta
, delta
);
4580 sig
= mono_method_signature_internal (cfg
->method
);
4581 if (sig
&& sig
->ret
&& MONO_TYPE_ISSTRUCT (sig
->ret
)) {
4582 cfg
->vret_addr
->inst_offset
+= delta
;
4584 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4585 MonoInst
*inst
= cfg
->args
[i
];
4587 inst
->inst_offset
+= delta
;
4591 * loads and stores based off the frame reg that (used to) lie
4592 * above the spill var area need to be increased by 'delta'
4593 * to make room for the spill vars.
4595 /* Need to find loads and stores to adjust that
4596 * are above where the spillvars were inserted, but
4597 * which are not the spillvar references themselves.
4599 * Idea - since all offsets from fp are positive, make
4600 * spillvar offsets negative to begin with so we can spot
4605 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
4609 if (cfg
->verbose_level
> 2) {
4610 g_print ("BASIC BLOCK %d:\n", bb
->block_num
);
4612 MONO_BB_FOR_EACH_INS (bb
, ins
) {
4616 if (cfg
->verbose_level
> 2) {
4617 mono_print_ins_index (ins_cnt
, ins
);
4619 /* The == mips_sp tests catch FP spills */
4620 if (MONO_IS_LOAD_MEMBASE(ins
) && ((ins
->inst_basereg
== mips_fp
) ||
4621 (ins
->inst_basereg
== mips_sp
))) {
4622 switch (ins
->opcode
) {
4623 case OP_LOADI8_MEMBASE
:
4624 case OP_LOADR8_MEMBASE
:
4631 } else if (MONO_IS_STORE_MEMBASE(ins
) && ((ins
->dreg
== mips_fp
) ||
4632 (ins
->dreg
== mips_sp
))) {
4633 switch (ins
->opcode
) {
4634 case OP_STOREI8_MEMBASE_REG
:
4635 case OP_STORER8_MEMBASE_REG
:
4636 case OP_STOREI8_MEMBASE_IMM
:
4644 if (((ins
->opcode
== OP_ADD_IMM
) || (ins
->opcode
== OP_IADD_IMM
)) && (ins
->sreg1
== cfg
->frame_reg
))
4647 if (ins
->inst_c0
>= threshold
) {
4648 ins
->inst_c0
+= delta
;
4649 if (cfg
->verbose_level
> 2) {
4651 mono_print_ins_index (ins_cnt
, ins
);
4654 else if (ins
->inst_c0
< 0) {
4655 /* Adj_c0 holds the size of the datatype. */
4656 ins
->inst_c0
= - ins
->inst_c0
- adj_c0
;
4657 if (cfg
->verbose_level
> 2) {
4659 mono_print_ins_index (ins_cnt
, ins
);
4662 g_assert (ins
->inst_c0
!= ra_offset
);
4665 if (ins
->inst_imm
>= threshold
) {
4666 ins
->inst_imm
+= delta
;
4667 if (cfg
->verbose_level
> 2) {
4669 mono_print_ins_index (ins_cnt
, ins
);
4672 g_assert (ins
->inst_c0
!= ra_offset
);
4682 * Stack frame layout:
4684 * ------------------- sp + cfg->stack_usage + cfg->param_area
4685 * param area incoming
4686 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4688 * ------------------- sp + cfg->stack_usage
4690 * ------------------- sp + cfg->stack_usage-4
4692 * ------------------- sp +
4693 * MonoLMF structure optional
4694 * ------------------- sp + cfg->arch.lmf_offset
4695 * saved registers s0-s8
4696 * ------------------- sp + cfg->arch.iregs_offset
4698 * ------------------- sp + cfg->param_area
4699 * param area outgoing
4700 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4702 * ------------------- sp
4706 mono_arch_emit_prolog (MonoCompile
*cfg
)
4708 MonoMethod
*method
= cfg
->method
;
4709 MonoMethodSignature
*sig
;
4711 int alloc_size
, pos
, i
, max_offset
;
4712 int alloc2_size
= 0;
4715 guint32 iregs_to_save
= 0;
4717 guint32 fregs_to_save
= 0;
4719 /* lmf_offset is the offset of the LMF from our stack pointer. */
4720 guint32 lmf_offset
= cfg
->arch
.lmf_offset
;
4724 sig
= mono_method_signature_internal (method
);
4725 cfg
->code_size
= 768 + sig
->param_count
* 20;
4726 code
= cfg
->native_code
= g_malloc (cfg
->code_size
);
4729 * compute max_offset in order to use short forward jumps.
4732 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
4733 MonoInst
*ins
= bb
->code
;
4734 bb
->max_offset
= max_offset
;
4736 MONO_BB_FOR_EACH_INS (bb
, ins
)
4737 max_offset
+= ins_get_size (ins
->opcode
);
4739 if (max_offset
> 0xffff)
4740 cfg
->arch
.long_branch
= TRUE
;
4743 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4744 * This means that we have to adjust the offsets inside instructions which reference
4745 * arguments received on the stack, since the initial offset doesn't take into
4746 * account spill slots.
4748 mips_adjust_stackframe (cfg
);
4750 /* Offset between current sp and the CFA */
4752 mono_emit_unwind_op_def_cfa (cfg
, code
, mips_sp
, cfa_offset
);
4754 /* stack_offset should not be changed here. */
4755 alloc_size
= cfg
->stack_offset
;
4756 cfg
->stack_usage
= alloc_size
;
4758 iregs_to_save
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
4761 fregs_to_save
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
4763 fregs_to_save
= MONO_ARCH_CALLEE_SAVED_FREGS
;
4764 fregs_to_save
|= (fregs_to_save
<< 1);
4767 /* If the stack size is too big, save 1024 bytes to start with
4768 * so the prologue can use imm16(reg) addressing, then allocate
4769 * the rest of the frame.
4771 if (alloc_size
> ((1 << 15) - 1024)) {
4772 alloc2_size
= alloc_size
- 1024;
4776 g_assert (mips_is_imm16 (-alloc_size
));
4777 mips_addiu (code
, mips_sp
, mips_sp
, -alloc_size
);
4778 cfa_offset
= alloc_size
;
4779 mono_emit_unwind_op_def_cfa_offset (cfg
, code
, cfa_offset
);
4782 if ((cfg
->flags
& MONO_CFG_HAS_CALLS
) || ALWAYS_SAVE_RA
) {
4783 int offset
= alloc_size
+ MIPS_RET_ADDR_OFFSET
;
4784 if (mips_is_imm16(offset
))
4785 mips_sw (code
, mips_ra
, mips_sp
, offset
);
4787 g_assert_not_reached ();
4789 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4790 mono_emit_unwind_op_offset (cfg
, code
, mips_ra
, offset
- cfa_offset
);
4793 /* XXX - optimize this later to not save all regs if LMF constructed */
4794 pos
= cfg
->arch
.iregs_offset
- alloc2_size
;
4796 if (iregs_to_save
) {
4797 /* save used registers in own stack frame (at pos) */
4798 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
4799 if (iregs_to_save
& (1 << i
)) {
4800 g_assert (pos
< (int)(cfg
->stack_usage
- sizeof(gpointer
)));
4801 g_assert (mips_is_imm16(pos
));
4802 MIPS_SW (code
, i
, mips_sp
, pos
);
4803 mono_emit_unwind_op_offset (cfg
, code
, i
, pos
- cfa_offset
);
4804 pos
+= SIZEOF_REGISTER
;
4809 // FIXME: Don't save registers twice if there is an LMF
4810 // s8 has to be special cased since it is overwritten with the updated value
4812 if (method
->save_lmf
) {
4813 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
4814 int offset
= lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, iregs
[i
]);
4815 g_assert (mips_is_imm16(offset
));
4816 if (MIPS_LMF_IREGMASK
& (1 << i
))
4817 MIPS_SW (code
, i
, mips_sp
, offset
);
4822 /* Save float registers */
4823 if (fregs_to_save
) {
4824 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
4825 if (fregs_to_save
& (1 << i
)) {
4826 g_assert (pos
< cfg
->stack_usage
- MIPS_STACK_ALIGNMENT
);
4827 g_assert (mips_is_imm16(pos
));
4828 mips_swc1 (code
, i
, mips_sp
, pos
);
4829 pos
+= sizeof (gulong
);
4834 if (method
->save_lmf
) {
4835 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
4836 int offset
= lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, fregs
[i
]);
4837 g_assert (mips_is_imm16(offset
));
4838 mips_swc1 (code
, i
, mips_sp
, offset
);
4843 if (cfg
->frame_reg
!= mips_sp
) {
4844 MIPS_MOVE (code
, cfg
->frame_reg
, mips_sp
);
4845 mono_emit_unwind_op_def_cfa (cfg
, code
, cfg
->frame_reg
, cfa_offset
);
4847 if (method
->save_lmf
) {
4848 int offset
= lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, iregs
[cfg
->frame_reg
]);
4849 g_assert (mips_is_imm16(offset
));
4850 MIPS_SW (code
, cfg
->frame_reg
, mips_sp
, offset
);
4854 /* store runtime generic context */
4855 if (cfg
->rgctx_var
) {
4856 MonoInst
*ins
= cfg
->rgctx_var
;
4858 g_assert (ins
->opcode
== OP_REGOFFSET
);
4860 g_assert (mips_is_imm16 (ins
->inst_offset
));
4861 mips_sw (code
, MONO_ARCH_RGCTX_REG
, ins
->inst_basereg
, ins
->inst_offset
);
4864 /* load arguments allocated to register from the stack */
4867 if (!cfg
->arch
.cinfo
)
4868 cfg
->arch
.cinfo
= get_call_info (cfg
->mempool
, sig
);
4869 cinfo
= cfg
->arch
.cinfo
;
4871 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
4872 ArgInfo
*ainfo
= &cinfo
->ret
;
4873 inst
= cfg
->vret_addr
;
4874 if (inst
->opcode
== OP_REGVAR
)
4875 MIPS_MOVE (code
, inst
->dreg
, ainfo
->reg
);
4876 else if (mips_is_imm16 (inst
->inst_offset
)) {
4877 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4879 mips_load_const (code
, mips_at
, inst
->inst_offset
);
4880 mips_addu (code
, mips_at
, mips_at
, inst
->inst_basereg
);
4881 mips_sw (code
, ainfo
->reg
, mips_at
, 0);
4885 if (sig
->call_convention
== MONO_CALL_VARARG
) {
4886 ArgInfo
*cookie
= &cinfo
->sig_cookie
;
4887 int offset
= alloc_size
+ cookie
->offset
;
4889 /* Save the sig cookie address */
4890 g_assert (cookie
->storage
== ArgOnStack
);
4892 g_assert (mips_is_imm16(offset
));
4893 mips_addi (code
, mips_at
, cfg
->frame_reg
, offset
);
4894 mips_sw (code
, mips_at
, cfg
->frame_reg
, cfg
->sig_cookie
- alloc2_size
);
4897 /* Keep this in sync with emit_load_volatile_arguments */
4898 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4899 ArgInfo
*ainfo
= cinfo
->args
+ i
;
4900 inst
= cfg
->args
[pos
];
4902 if (cfg
->verbose_level
> 2)
4903 g_print ("Saving argument %d (type: %d)\n", i
, ainfo
->storage
);
4904 if (inst
->opcode
== OP_REGVAR
) {
4905 /* Argument ends up in a register */
4906 if (ainfo
->storage
== ArgInIReg
)
4907 MIPS_MOVE (code
, inst
->dreg
, ainfo
->reg
);
4908 else if (ainfo
->storage
== ArgInFReg
) {
4909 g_assert_not_reached();
4911 ppc_fmr (code
, inst
->dreg
, ainfo
->reg
);
4914 else if (ainfo
->storage
== ArgOnStack
) {
4915 int offset
= cfg
->stack_usage
+ ainfo
->offset
;
4916 g_assert (mips_is_imm16(offset
));
4917 mips_lw (code
, inst
->dreg
, mips_sp
, offset
);
4919 g_assert_not_reached ();
4921 if (cfg
->verbose_level
> 2)
4922 g_print ("Argument %d assigned to register %s\n", pos
, mono_arch_regname (inst
->dreg
));
4924 /* Argument ends up on the stack */
4925 if (ainfo
->storage
== ArgInIReg
) {
4927 /* Incoming parameters should be above this frame */
4928 if (cfg
->verbose_level
> 2)
4929 g_print ("stack slot at %d of %d+%d\n",
4930 inst
->inst_offset
, alloc_size
, alloc2_size
);
4931 /* g_assert (inst->inst_offset >= alloc_size); */
4932 g_assert (inst
->inst_basereg
== cfg
->frame_reg
);
4933 basereg_offset
= inst
->inst_offset
- alloc2_size
;
4934 g_assert (mips_is_imm16 (basereg_offset
));
4935 switch (ainfo
->size
) {
4937 mips_sb (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
);
4940 mips_sh (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
);
4944 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
);
4947 #if (SIZEOF_REGISTER == 4)
4948 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
+ ls_word_offset
);
4949 mips_sw (code
, ainfo
->reg
+ 1, inst
->inst_basereg
, basereg_offset
+ ms_word_offset
);
4950 #elif (SIZEOF_REGISTER == 8)
4951 mips_sd (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
);
4955 g_assert_not_reached ();
4958 } else if (ainfo
->storage
== ArgOnStack
) {
4960 * Argument comes in on the stack, and ends up on the stack
4961 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4962 * 8 and 16 bit quantities. Shorten them in place.
4964 g_assert (mips_is_imm16 (inst
->inst_offset
));
4965 switch (ainfo
->size
) {
4967 mips_lw (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4968 mips_sb (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4971 mips_lw (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4972 mips_sh (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4979 g_assert_not_reached ();
4981 } else if (ainfo
->storage
== ArgInFReg
) {
4982 g_assert (mips_is_imm16 (inst
->inst_offset
));
4983 g_assert (mips_is_imm16 (inst
->inst_offset
+4));
4984 if (ainfo
->size
== 8) {
4985 #if _MIPS_SIM == _ABIO32
4986 mips_swc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+ ls_word_offset
);
4987 mips_swc1 (code
, ainfo
->reg
+1, inst
->inst_basereg
, inst
->inst_offset
+ ms_word_offset
);
4988 #elif _MIPS_SIM == _ABIN32
4989 mips_sdc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4992 else if (ainfo
->size
== 4)
4993 mips_swc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4995 g_assert_not_reached ();
4996 } else if (ainfo
->storage
== ArgStructByVal
) {
4998 int doffset
= inst
->inst_offset
;
5000 g_assert (mips_is_imm16 (inst
->inst_offset
));
5001 g_assert (mips_is_imm16 (inst
->inst_offset
+ ainfo
->size
* sizeof (target_mgreg_t
)));
5002 /* Push the argument registers into their stack slots */
5003 for (i
= 0; i
< ainfo
->size
; ++i
) {
5004 g_assert (mips_is_imm16(doffset
));
5005 MIPS_SW (code
, ainfo
->reg
+ i
, inst
->inst_basereg
, doffset
);
5006 doffset
+= SIZEOF_REGISTER
;
5008 } else if (ainfo
->storage
== ArgStructByAddr
) {
5009 g_assert (mips_is_imm16 (inst
->inst_offset
));
5010 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5011 code
= emit_memcpy (code
, ainfo
->vtsize
* sizeof (target_mgreg_t
), inst
->inst_basereg
, inst
->inst_offset
, ainfo
->reg
, 0);
5013 g_assert_not_reached ();
5018 if (method
->save_lmf
) {
5019 mips_load_const (code
, mips_at
, MIPS_LMF_MAGIC1
);
5020 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, magic
));
5022 /* This can/will clobber the a0-a3 registers */
5023 mips_call (code
, mips_t9
, (gpointer
)mono_get_lmf_addr
);
5025 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5026 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
)));
5027 mips_sw (code
, mips_v0
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
5028 /* new_lmf->previous_lmf = *lmf_addr */
5029 mips_lw (code
, mips_at
, mips_v0
, 0);
5030 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
)));
5031 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
5032 /* *(lmf_addr) = sp + lmf_offset */
5033 g_assert (mips_is_imm16(lmf_offset
));
5034 mips_addiu (code
, mips_at
, mips_sp
, lmf_offset
);
5035 mips_sw (code
, mips_at
, mips_v0
, 0);
5037 /* save method info */
5038 mips_load_const (code
, mips_at
, method
);
5039 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, method
)));
5040 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, method
));
5042 /* save the current IP */
5043 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_IP
, NULL
);
5044 mips_load_const (code
, mips_at
, 0x01010101);
5045 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, eip
));
5049 if (mips_is_imm16 (-alloc2_size
)) {
5050 mips_addu (code
, mips_sp
, mips_sp
, -alloc2_size
);
5053 mips_load_const (code
, mips_at
, -alloc2_size
);
5054 mips_addu (code
, mips_sp
, mips_sp
, mips_at
);
5056 alloc_size
+= alloc2_size
;
5057 cfa_offset
+= alloc2_size
;
5058 if (cfg
->frame_reg
!= mips_sp
)
5059 MIPS_MOVE (code
, cfg
->frame_reg
, mips_sp
);
5061 mono_emit_unwind_op_def_cfa_offset (cfg
, code
, cfa_offset
);
5064 set_code_cursor (cfg
, code
);
5070 mono_arch_emit_epilog_sub (MonoCompile
*cfg
)
5072 guint8
*code
= NULL
;
5073 MonoMethod
*method
= cfg
->method
;
5075 int max_epilog_size
= 16 + 20*4;
5076 int alloc2_size
= 0;
5077 guint32 iregs_to_restore
;
5079 guint32 fregs_to_restore
;
5082 if (cfg
->method
->save_lmf
)
5083 max_epilog_size
+= 128;
5085 realloc_code (cfg
, max_epilog_size
);
5087 code
= cfg
->native_code
+ cfg
->code_len
;
5089 if (cfg
->frame_reg
!= mips_sp
) {
5090 MIPS_MOVE (code
, mips_sp
, cfg
->frame_reg
);
5092 /* If the stack frame is really large, deconstruct it in two steps */
5093 if (cfg
->stack_usage
> ((1 << 15) - 1024)) {
5094 alloc2_size
= cfg
->stack_usage
- 1024;
5095 /* partially deconstruct the stack */
5096 mips_load_const (code
, mips_at
, alloc2_size
);
5097 mips_addu (code
, mips_sp
, mips_sp
, mips_at
);
5099 int pos
= cfg
->arch
.iregs_offset
- alloc2_size
;
5100 iregs_to_restore
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
5101 if (iregs_to_restore
) {
5102 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
5103 if (iregs_to_restore
& (1 << i
)) {
5104 g_assert (mips_is_imm16(pos
));
5105 MIPS_LW (code
, i
, mips_sp
, pos
);
5106 pos
+= SIZEOF_REGISTER
;
5113 fregs_to_restore
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
5115 fregs_to_restore
= MONO_ARCH_CALLEE_SAVED_FREGS
;
5116 fregs_to_restore
|= (fregs_to_restore
<< 1);
5118 if (fregs_to_restore
) {
5119 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
5120 if (fregs_to_restore
& (1 << i
)) {
5121 g_assert (pos
< cfg
->stack_usage
- MIPS_STACK_ALIGNMENT
);
5122 g_assert (mips_is_imm16(pos
));
5123 mips_lwc1 (code
, i
, mips_sp
, pos
);
5130 /* Unlink the LMF if necessary */
5131 if (method
->save_lmf
) {
5132 int lmf_offset
= cfg
->arch
.lmf_offset
;
5134 /* t0 = current_lmf->previous_lmf */
5135 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
)));
5136 mips_lw (code
, mips_temp
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
5138 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
)));
5139 mips_lw (code
, mips_t1
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
5140 /* (*lmf_addr) = previous_lmf */
5141 mips_sw (code
, mips_temp
, mips_t1
, 0);
5145 /* Restore the fp */
5146 mips_lw (code
, mips_fp
, mips_sp
, cfg
->stack_usage
+ MIPS_FP_ADDR_OFFSET
);
5149 if ((cfg
->flags
& MONO_CFG_HAS_CALLS
) || ALWAYS_SAVE_RA
) {
5150 g_assert (mips_is_imm16(cfg
->stack_usage
- alloc2_size
+ MIPS_RET_ADDR_OFFSET
));
5151 mips_lw (code
, mips_ra
, mips_sp
, cfg
->stack_usage
- alloc2_size
+ MIPS_RET_ADDR_OFFSET
);
5153 /* Restore the stack pointer */
5154 g_assert (mips_is_imm16(cfg
->stack_usage
- alloc2_size
));
5155 mips_addiu (code
, mips_sp
, mips_sp
, cfg
->stack_usage
- alloc2_size
);
5157 /* Caller will emit either return or tail-call sequence */
5159 set_code_cursor (cfg
, code
);
5165 mono_arch_emit_epilog (MonoCompile
*cfg
)
5167 guint8
*code
= mono_arch_emit_epilog_sub (cfg
);
5169 mips_jr (code
, mips_ra
);
5172 set_code_cursor (cfg
, code
);
5175 /* remove once throw_exception_by_name is eliminated */
5178 exception_id_by_name (const char *name
)
5180 if (strcmp (name
, "IndexOutOfRangeException") == 0)
5181 return MONO_EXC_INDEX_OUT_OF_RANGE
;
5182 if (strcmp (name
, "OverflowException") == 0)
5183 return MONO_EXC_OVERFLOW
;
5184 if (strcmp (name
, "ArithmeticException") == 0)
5185 return MONO_EXC_ARITHMETIC
;
5186 if (strcmp (name
, "DivideByZeroException") == 0)
5187 return MONO_EXC_DIVIDE_BY_ZERO
;
5188 if (strcmp (name
, "InvalidCastException") == 0)
5189 return MONO_EXC_INVALID_CAST
;
5190 if (strcmp (name
, "NullReferenceException") == 0)
5191 return MONO_EXC_NULL_REF
;
5192 if (strcmp (name
, "ArrayTypeMismatchException") == 0)
5193 return MONO_EXC_ARRAY_TYPE_MISMATCH
;
5194 if (strcmp (name
, "ArgumentException") == 0)
5195 return MONO_EXC_ARGUMENT
;
5196 g_error ("Unknown intrinsic exception %s\n", name
);
5202 mono_arch_emit_exceptions (MonoCompile
*cfg
)
5205 MonoJumpInfo
*patch_info
;
5208 const guint8
* exc_throw_pos
[MONO_EXC_INTRINS_NUM
] = {NULL
};
5209 guint8 exc_throw_found
[MONO_EXC_INTRINS_NUM
] = {0};
5210 int max_epilog_size
= 50;
5212 /* count the number of exception infos */
5215 * make sure we have enough space for exceptions
5216 * 24 is the simulated call to throw_exception_by_name
5218 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5220 if (patch_info
->type
== MONO_PATCH_INFO_EXC
) {
5221 i
= exception_id_by_name (patch_info
->data
.target
);
5222 g_assert (i
< MONO_EXC_INTRINS_NUM
);
5223 if (!exc_throw_found
[i
]) {
5224 max_epilog_size
+= 12;
5225 exc_throw_found
[i
] = TRUE
;
5231 code
= realloc_code (cfg
, max_epilog_size
);
5233 /* add code to raise exceptions */
5234 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5235 switch (patch_info
->type
) {
5236 case MONO_PATCH_INFO_EXC
: {
5237 g_assert_not_reached();
5246 set_code_cursor (cfg
, code
);
5251 mono_arch_finish_init (void)
5256 mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
, int this_reg
, int this_type
, int vt_reg
)
5258 int this_dreg
= mips_a0
;
5261 this_dreg
= mips_a1
;
5263 /* add the this argument */
5264 if (this_reg
!= -1) {
5266 MONO_INST_NEW (cfg
, this_ins
, OP_MOVE
);
5267 this_ins
->type
= this_type
;
5268 this_ins
->sreg1
= this_reg
;
5269 this_ins
->dreg
= mono_alloc_ireg (cfg
);
5270 mono_bblock_add_inst (cfg
->cbb
, this_ins
);
5271 mono_call_inst_add_outarg_reg (cfg
, inst
, this_ins
->dreg
, this_dreg
, FALSE
);
5276 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
5277 vtarg
->type
= STACK_MP
;
5278 vtarg
->sreg1
= vt_reg
;
5279 vtarg
->dreg
= mono_alloc_ireg (cfg
);
5280 mono_bblock_add_inst (cfg
->cbb
, vtarg
);
5281 mono_call_inst_add_outarg_reg (cfg
, inst
, vtarg
->dreg
, mips_a0
, FALSE
);
5286 mono_arch_get_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
5288 MonoInst
*ins
= NULL
;
5294 mono_arch_emit_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
5300 mono_arch_context_get_int_reg (MonoContext
*ctx
, int reg
)
5302 return ctx
->sc_regs
[reg
];
5305 #define ENABLE_WRONG_METHOD_CHECK 0
5307 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5308 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5310 #define LOADSTORE_SIZE 4
5311 #define JUMP_IMM_SIZE 16
5312 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5313 #define LOAD_CONST_SIZE 8
5314 #define JUMP_JR_SIZE 8
5317 * LOCKING: called with the domain lock held
5320 mono_arch_build_imt_trampoline (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
,
5321 gpointer fail_tramp
)
5325 guint8
*code
, *start
, *patch
;
5327 for (i
= 0; i
< count
; ++i
) {
5328 MonoIMTCheckItem
*item
= imt_entries
[i
];
5330 if (item
->is_equals
) {
5331 if (item
->check_target_idx
) {
5332 item
->chunk_size
+= LOAD_CONST_SIZE
+ BR_SIZE
+ JUMP_JR_SIZE
;
5333 if (item
->has_target_code
)
5334 item
->chunk_size
+= LOAD_CONST_SIZE
;
5336 item
->chunk_size
+= LOADSTORE_SIZE
;
5339 item
->chunk_size
+= LOAD_CONST_SIZE
+ BR_SIZE
+ JUMP_IMM32_SIZE
+
5340 LOADSTORE_SIZE
+ JUMP_IMM32_SIZE
;
5341 if (!item
->has_target_code
)
5342 item
->chunk_size
+= LOADSTORE_SIZE
;
5344 item
->chunk_size
+= LOADSTORE_SIZE
+ JUMP_JR_SIZE
;
5345 #if ENABLE_WRONG_METHOD_CHECK
5346 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
+ 4;
5351 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
;
5352 imt_entries
[item
->check_target_idx
]->compare_done
= TRUE
;
5354 size
+= item
->chunk_size
;
5356 /* the initial load of the vtable address */
5357 size
+= MIPS_LOAD_SEQUENCE_LENGTH
;
5359 code
= mono_method_alloc_generic_virtual_trampoline (domain
, size
);
5361 code
= mono_domain_code_reserve (domain
, size
);
5365 /* t7 points to the vtable */
5366 mips_load_const (code
, mips_t7
, (gsize
)(& (vtable
->vtable
[0])));
5368 for (i
= 0; i
< count
; ++i
) {
5369 MonoIMTCheckItem
*item
= imt_entries
[i
];
5371 item
->code_target
= code
;
5372 if (item
->is_equals
) {
5373 if (item
->check_target_idx
) {
5374 mips_load_const (code
, mips_temp
, (gsize
)item
->key
);
5375 item
->jmp_code
= code
;
5376 mips_bne (code
, mips_temp
, MONO_ARCH_IMT_REG
, 0);
5378 if (item
->has_target_code
) {
5379 mips_load_const (code
, mips_t9
,
5380 item
->value
.target_code
);
5383 mips_lw (code
, mips_t9
, mips_t7
,
5384 (sizeof (target_mgreg_t
) * item
->value
.vtable_slot
));
5386 mips_jr (code
, mips_t9
);
5390 mips_load_const (code
, mips_temp
, (gsize
)item
->key
);
5392 mips_bne (code
, mips_temp
, MONO_ARCH_IMT_REG
, 0);
5394 if (item
->has_target_code
) {
5395 mips_load_const (code
, mips_t9
,
5396 item
->value
.target_code
);
5399 mips_load_const (code
, mips_at
,
5400 & (vtable
->vtable
[item
->value
.vtable_slot
]));
5401 mips_lw (code
, mips_t9
, mips_at
, 0);
5403 mips_jr (code
, mips_t9
);
5405 mips_patch ((guint32
*)(void *)patch
, (guint32
)code
);
5406 mips_load_const (code
, mips_t9
, fail_tramp
);
5407 mips_jr (code
, mips_t9
);
5410 /* enable the commented code to assert on wrong method */
5411 #if ENABLE_WRONG_METHOD_CHECK
5412 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5413 ppc_compare_log (code
, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5415 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5417 mips_lw (code
, mips_t9
, mips_t7
,
5418 (sizeof (target_mgreg_t
) * item
->value
.vtable_slot
));
5419 mips_jr (code
, mips_t9
);
5422 #if ENABLE_WRONG_METHOD_CHECK
5423 ppc_patch (patch
, code
);
5429 mips_load_const (code
, mips_temp
, (gulong
)item
->key
);
5430 mips_slt (code
, mips_temp
, MONO_ARCH_IMT_REG
, mips_temp
);
5432 item
->jmp_code
= code
;
5433 mips_beq (code
, mips_temp
, mips_zero
, 0);
5437 /* patch the branches to get to the target items */
5438 for (i
= 0; i
< count
; ++i
) {
5439 MonoIMTCheckItem
*item
= imt_entries
[i
];
5440 if (item
->jmp_code
&& item
->check_target_idx
) {
5441 mips_patch ((guint32
*)item
->jmp_code
,
5442 (guint32
)imt_entries
[item
->check_target_idx
]->code_target
);
5447 UnlockedAdd (&mono_stats
.imt_trampolines_size
, code
- start
);
5448 g_assert (code
- start
<= size
);
5449 mono_arch_flush_icache (start
, size
);
5450 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE
, NULL
));
5452 mono_tramp_info_register (mono_tramp_info_create (NULL
, start
, code
- start
, NULL
, NULL
), domain
);
5458 mono_arch_find_imt_method (host_mgreg_t
*regs
, guint8
*code
)
5460 return (MonoMethod
*) regs
[MONO_ARCH_IMT_REG
];
5464 mono_arch_find_static_call_vtable (host_mgreg_t
*regs
, guint8
*code
)
5466 return (MonoVTable
*) regs
[MONO_ARCH_RGCTX_REG
];
5469 /* Soft Debug support */
5470 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5473 * mono_arch_set_breakpoint:
5475 * See mini-amd64.c for docs.
5478 mono_arch_set_breakpoint (MonoJitInfo
*ji
, guint8
*ip
)
5481 guint32 addr
= (guint32
)bp_trigger_page
;
5483 mips_load_const (code
, mips_t9
, addr
);
5484 mips_lw (code
, mips_t9
, mips_t9
, 0);
5486 mono_arch_flush_icache (ip
, code
- ip
);
5490 * mono_arch_clear_breakpoint:
5492 * See mini-amd64.c for docs.
5495 mono_arch_clear_breakpoint (MonoJitInfo
*ji
, guint8
*ip
)
5503 mono_arch_flush_icache (ip
, code
- ip
);
5507 * mono_arch_start_single_stepping:
5509 * See mini-amd64.c for docs.
5512 mono_arch_start_single_stepping (void)
5514 mono_mprotect (ss_trigger_page
, mono_pagesize (), 0);
5518 * mono_arch_stop_single_stepping:
5520 * See mini-amd64.c for docs.
5523 mono_arch_stop_single_stepping (void)
5525 mono_mprotect (ss_trigger_page
, mono_pagesize (), MONO_MMAP_READ
);
5529 * mono_arch_is_single_step_event:
5531 * See mini-amd64.c for docs.
5534 mono_arch_is_single_step_event (void *info
, void *sigctx
)
5536 siginfo_t
* sinfo
= (siginfo_t
*) info
;
5537 /* Sometimes the address is off by 4 */
5538 if (sinfo
->si_addr
>= ss_trigger_page
&& (guint8
*)sinfo
->si_addr
<= (guint8
*)ss_trigger_page
+ 128)
5545 * mono_arch_is_breakpoint_event:
5547 * See mini-amd64.c for docs.
5550 mono_arch_is_breakpoint_event (void *info
, void *sigctx
)
5552 siginfo_t
* sinfo
= (siginfo_t
*) info
;
5553 /* Sometimes the address is off by 4 */
5554 if (sinfo
->si_addr
>= bp_trigger_page
&& (guint8
*)sinfo
->si_addr
<= (guint8
*)bp_trigger_page
+ 128)
5561 * mono_arch_skip_breakpoint:
5563 * See mini-amd64.c for docs.
5566 mono_arch_skip_breakpoint (MonoContext
*ctx
, MonoJitInfo
*ji
)
5568 MONO_CONTEXT_SET_IP (ctx
, (guint8
*)MONO_CONTEXT_GET_IP (ctx
) + 4);
5572 * mono_arch_skip_single_step:
5574 * See mini-amd64.c for docs.
5577 mono_arch_skip_single_step (MonoContext
*ctx
)
5579 MONO_CONTEXT_SET_IP (ctx
, (guint8
*)MONO_CONTEXT_GET_IP (ctx
) + 4);
5583 * mono_arch_get_seq_point_info:
5585 * See mini-amd64.c for docs.
5588 mono_arch_get_seq_point_info (MonoDomain
*domain
, guint8
*code
)
5594 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5597 mono_arch_opcode_supported (int opcode
)
5603 mono_arch_tailcall_supported (MonoCompile
*cfg
, MonoMethodSignature
*caller_sig
, MonoMethodSignature
*callee_sig
, gboolean virtual_
)
5609 mono_arch_load_function (MonoJitICallId jit_icall_id
)