2 * mini-mips.c: MIPS backend for the Mono code generator
5 * Mark Mason (mason@broadcom.com)
7 * Based on mini-ppc.c by
8 * Paolo Molaro (lupus@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2003 Ximian, Inc.
16 #include <asm/cachectl.h>
18 #include <mono/metadata/abi-details.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/utils/mono-mmap.h>
22 #include <mono/utils/mono-hwcap.h>
24 #include <mono/arch/mips/mips-codegen.h>
26 #include "mini-mips.h"
31 #define SAVE_FP_REGS 0
33 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
35 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
36 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
37 remember to update cpu-mips.md if you change this */
39 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
40 #define mips_call(c,D,v) do { \
41 guint32 _target = (guint32)(v); \
42 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
43 mips_load_const (c, D, _target); \
44 mips_jalr (c, D, mips_ra); \
47 mips_jumpl (c, _target >> 2); \
59 /* This mutex protects architecture specific caches */
60 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
61 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
62 static mono_mutex_t mini_arch_mutex
;
64 int mono_exc_esp_offset
= 0;
65 static int tls_mode
= TLS_MODE_DETECT
;
66 static int lmf_pthread_key
= -1;
67 static int monothread_key
= -1;
69 /* Whenever the host is little-endian */
70 static int little_endian
;
71 /* Index of ms word/register */
72 static int ls_word_idx
;
73 /* Index of ls word/register */
74 static int ms_word_idx
;
75 /* Same for offsets */
76 static int ls_word_offset
;
77 static int ms_word_offset
;
80 * The code generated for sequence points reads from this location, which is
81 * made read-only when single stepping is enabled.
83 static gpointer ss_trigger_page
;
85 /* Enabled breakpoints read from this trigger page */
86 static gpointer bp_trigger_page
;
89 #define DEBUG(a) if (cfg->verbose_level > 1) a
95 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
97 code = mips_emit_exc_by_name (code, exc_name); \
98 cfg->bb_exit->max_offset += 16; \
102 #define emit_linuxthreads_tls(code,dreg,key) do {\
104 off1 = offsets_from_pthread_key ((key), &off2); \
105 g_assert_not_reached (); \
106 ppc_lwz ((code), (dreg), off1, ppc_r2); \
107 ppc_lwz ((code), (dreg), off2, (dreg)); \
111 #define emit_tls_access(code,dreg,key) do { \
112 switch (tls_mode) { \
113 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
114 default: g_assert_not_reached (); \
118 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
120 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
121 inst->type = STACK_R8; \
123 inst->inst_p0 = (void*)(addr); \
124 mono_bblock_add_inst (cfg->cbb, inst); \
127 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
128 || ((ins)->opcode == OP_ICOMPARE) \
129 || ((ins)->opcode == OP_LCOMPARE)))
130 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
131 || ((ins)->opcode == OP_ICOMPARE_IMM) \
132 || ((ins)->opcode == OP_LCOMPARE_IMM)))
134 #define INS_REWRITE(ins, op, _s1, _s2) do { \
137 ins->opcode = (op); \
142 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
144 ins->opcode = (op); \
146 ins->inst_imm = (_imm); \
150 typedef struct InstList InstList
;
168 guint16 vtsize
; /* in param area */
171 guint8 size
: 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
180 gboolean vtype_retaddr
;
189 void patch_lui_addiu(guint32
*ip
, guint32 val
);
190 guint8
*mono_arch_emit_epilog_sub (MonoCompile
*cfg
, guint8
*code
);
191 guint8
*mips_emit_cond_branch (MonoCompile
*cfg
, guint8
*code
, int op
, MonoInst
*ins
);
192 void mips_adjust_stackframe(MonoCompile
*cfg
);
193 void mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
, int this_reg
, int this_type
, int vt_reg
);
194 MonoInst
*mono_arch_get_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
);
197 /* Not defined in asm/cachectl.h */
198 int cacheflush(char *addr
, int nbytes
, int cache
);
201 mono_arch_flush_icache (guint8
*code
, gint size
)
203 /* Linux/MIPS specific */
204 cacheflush ((char*)code
, size
, BCACHE
);
208 mono_arch_flush_register_windows (void)
213 mono_arch_is_inst_imm (gint64 imm
)
219 mips_emit_exc_by_name(guint8
*code
, const char *name
)
222 MonoClass
*exc_class
;
224 exc_class
= mono_class_load_from_name (mono_defaults
.corlib
, "System", name
);
226 mips_load_const (code
, mips_a0
, exc_class
->type_token
);
227 addr
= mono_get_throw_corlib_exception ();
228 mips_call (code
, mips_t9
, addr
);
234 mips_emit_load_const(guint8
*code
, int dreg
, mgreg_t v
)
236 if (mips_is_imm16 (v
))
237 mips_addiu (code
, dreg
, mips_zero
, ((guint32
)v
) & 0xffff);
239 #if SIZEOF_REGISTER == 8
241 /* v is not a sign-extended 32-bit value */
242 mips_lui (code
, dreg
, mips_zero
, (guint32
)((v
>> (32+16)) & 0xffff));
243 mips_ori (code
, dreg
, dreg
, (guint32
)((v
>> (32)) & 0xffff));
244 mips_dsll (code
, dreg
, dreg
, 16);
245 mips_ori (code
, dreg
, dreg
, (guint32
)((v
>> (16)) & 0xffff));
246 mips_dsll (code
, dreg
, dreg
, 16);
247 mips_ori (code
, dreg
, dreg
, (guint32
)(v
& 0xffff));
251 if (((guint32
)v
) & (1 << 15)) {
252 mips_lui (code
, dreg
, mips_zero
, (((guint32
)v
)>>16)+1);
255 mips_lui (code
, dreg
, mips_zero
, (((guint32
)v
)>>16));
257 if (((guint32
)v
) & 0xffff)
258 mips_addiu (code
, dreg
, dreg
, ((guint32
)v
) & 0xffff);
264 mips_emit_cond_branch (MonoCompile
*cfg
, guint8
*code
, int op
, MonoInst
*ins
)
267 if (cfg
->arch
.long_branch
) {
270 /* Invert test and emit branch around jump */
273 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, br_offset
);
277 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, br_offset
);
281 mips_bltz (code
, ins
->sreg1
, br_offset
);
285 mips_blez (code
, ins
->sreg1
, br_offset
);
289 mips_bgtz (code
, ins
->sreg1
, br_offset
);
293 mips_bgez (code
, ins
->sreg1
, br_offset
);
297 g_assert_not_reached ();
299 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
300 MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
301 mips_lui (code
, mips_at
, mips_zero
, 0);
302 mips_addiu (code
, mips_at
, mips_at
, 0);
303 mips_jr (code
, mips_at
);
307 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
308 MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
311 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, 0);
315 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, 0);
319 mips_bgez (code
, ins
->sreg1
, 0);
323 mips_bgtz (code
, ins
->sreg1
, 0);
327 mips_blez (code
, ins
->sreg1
, 0);
331 mips_bltz (code
, ins
->sreg1
, 0);
335 g_assert_not_reached ();
341 /* XXX - big-endian dependent? */
343 patch_lui_addiu(guint32
*ip
, guint32 val
)
345 guint16
*__lui_addiu
= (guint16
*)(void *)(ip
);
348 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
349 ip
, ((guint32
*)ip
)[0], ((guint32
*)ip
)[1], val
);
352 if (((guint32
)(val
)) & (1 << 15))
353 __lui_addiu
[MINI_LS_WORD_IDX
] = ((((guint32
)(val
)) >> 16) & 0xffff) + 1;
355 __lui_addiu
[MINI_LS_WORD_IDX
] = (((guint32
)(val
)) >> 16) & 0xffff;
356 __lui_addiu
[MINI_LS_WORD_IDX
+ 2] = ((guint32
)(val
)) & 0xffff;
357 mono_arch_flush_icache ((guint8
*)ip
, 8);
362 mips_patch (guint32
*code
, guint32 target
)
365 guint32 op
= ins
>> 26;
366 guint32 diff
, offset
;
368 g_assert (trap_target
!= target
);
369 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
371 case 0x00: /* jr ra */
372 if (ins
== 0x3e00008)
374 g_assert_not_reached ();
378 g_assert (!(target
& 0x03));
379 g_assert ((target
& 0xfc000000) == (((guint32
)code
) & 0xfc000000));
380 ins
= (ins
& 0xfc000000) | (((target
) >> 2) & 0x03ffffff);
382 mono_arch_flush_icache ((guint8
*)code
, 4);
384 case 0x01: /* BLTZ */
387 case 0x06: /* BLEZ */
388 case 0x07: /* BGTZ */
389 case 0x11: /* bc1t */
390 diff
= target
- (guint32
)(code
+ 1);
391 g_assert (((diff
& 0x0003ffff) == diff
) || ((diff
| 0xfffc0000) == diff
));
392 g_assert (!(diff
& 0x03));
393 offset
= ((gint32
)diff
) >> 2;
394 if (((int)offset
) != ((int)(short)offset
))
395 g_assert (((int)offset
) == ((int)(short)offset
));
396 ins
= (ins
& 0xffff0000) | (offset
& 0x0000ffff);
398 mono_arch_flush_icache ((guint8
*)code
, 4);
400 case 0x0f: /* LUI / ADDIU pair */
401 g_assert ((code
[1] >> 26) == 0x9);
402 patch_lui_addiu (code
, target
);
403 mono_arch_flush_icache ((guint8
*)code
, 8);
407 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op
, ins
, code
);
408 g_assert_not_reached ();
414 offsets_from_pthread_key (guint32 key
, int *offset2
)
418 *offset2
= idx2
* sizeof (gpointer
);
419 return 284 + idx1
* sizeof (gpointer
);
423 static void mono_arch_compute_omit_fp (MonoCompile
*cfg
);
426 mono_arch_regname (int reg
) {
427 #if _MIPS_SIM == _ABIO32
428 static const char * rnames
[] = {
429 "zero", "at", "v0", "v1",
430 "a0", "a1", "a2", "a3",
431 "t0", "t1", "t2", "t3",
432 "t4", "t5", "t6", "t7",
433 "s0", "s1", "s2", "s3",
434 "s4", "s5", "s6", "s7",
435 "t8", "t9", "k0", "k1",
436 "gp", "sp", "fp", "ra"
438 #elif _MIPS_SIM == _ABIN32
439 static const char * rnames
[] = {
440 "zero", "at", "v0", "v1",
441 "a0", "a1", "a2", "a3",
442 "a4", "a5", "a6", "a7",
443 "t0", "t1", "t2", "t3",
444 "s0", "s1", "s2", "s3",
445 "s4", "s5", "s6", "s7",
446 "t8", "t9", "k0", "k1",
447 "gp", "sp", "fp", "ra"
450 if (reg
>= 0 && reg
< 32)
456 mono_arch_fregname (int reg
) {
457 static const char * rnames
[] = {
458 "f0", "f1", "f2", "f3",
459 "f4", "f5", "f6", "f7",
460 "f8", "f9", "f10", "f11",
461 "f12", "f13", "f14", "f15",
462 "f16", "f17", "f18", "f19",
463 "f20", "f21", "f22", "f23",
464 "f24", "f25", "f26", "f27",
465 "f28", "f29", "f30", "f31"
467 if (reg
>= 0 && reg
< 32)
472 /* this function overwrites at */
474 emit_memcpy (guint8
*code
, int size
, int dreg
, int doffset
, int sreg
, int soffset
)
476 /* XXX write a loop, not an unrolled loop */
478 mips_lw (code
, mips_at
, sreg
, soffset
);
479 mips_sw (code
, mips_at
, dreg
, doffset
);
488 * mono_arch_get_argument_info:
489 * @csig: a method signature
490 * @param_count: the number of parameters to consider
491 * @arg_info: an array to store the result infos
493 * Gathers information on parameters such as size, alignment and
494 * padding. arg_info should be large enought to hold param_count + 1 entries.
496 * Returns the size of the activation frame.
499 mono_arch_get_argument_info (MonoMethodSignature
*csig
, int param_count
, MonoJitArgumentInfo
*arg_info
)
501 int k
, frame_size
= 0;
502 guint32 size
, align
, pad
;
505 if (MONO_TYPE_ISSTRUCT (csig
->ret
)) {
506 frame_size
+= sizeof (gpointer
);
510 arg_info
[0].offset
= offset
;
513 frame_size
+= sizeof (gpointer
);
517 arg_info
[0].size
= frame_size
;
519 for (k
= 0; k
< param_count
; k
++) {
520 size
= mini_type_stack_size_full (csig
->params
[k
], &align
, csig
->pinvoke
);
522 /* ignore alignment for now */
525 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
526 arg_info
[k
].pad
= pad
;
528 arg_info
[k
+ 1].pad
= 0;
529 arg_info
[k
+ 1].size
= size
;
531 arg_info
[k
+ 1].offset
= offset
;
535 align
= MONO_ARCH_FRAME_ALIGNMENT
;
536 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
537 arg_info
[k
].pad
= pad
;
542 /* The delegate object plus 3 params */
543 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
546 get_delegate_invoke_impl (MonoTrampInfo
**info
, gboolean has_target
, gboolean param_count
)
548 guint8
*code
, *start
;
551 start
= code
= mono_global_codeman_reserve (16);
553 /* Replace the this argument with the target */
554 mips_lw (code
, mips_temp
, mips_a0
, MONO_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
555 mips_lw (code
, mips_a0
, mips_a0
, MONO_STRUCT_OFFSET (MonoDelegate
, target
));
556 mips_jr (code
, mips_temp
);
559 g_assert ((code
- start
) <= 16);
561 mono_arch_flush_icache (start
, 16);
565 size
= 16 + param_count
* 4;
566 start
= code
= mono_global_codeman_reserve (size
);
568 mips_lw (code
, mips_temp
, mips_a0
, MONO_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
569 /* slide down the arguments */
570 for (i
= 0; i
< param_count
; ++i
) {
571 mips_move (code
, mips_a0
+ i
, mips_a0
+ i
+ 1);
573 mips_jr (code
, mips_temp
);
576 g_assert ((code
- start
) <= size
);
578 mono_arch_flush_icache (start
, size
);
582 *info
= mono_tramp_info_create ("delegate_invoke_impl_has_target", start
, code
- start
, NULL
, NULL
);
584 char *name
= g_strdup_printf ("delegate_invoke_impl_target_%d", param_count
);
585 *info
= mono_tramp_info_create (name
, start
, code
- start
, NULL
, NULL
);
593 * mono_arch_get_delegate_invoke_impls:
595 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
599 mono_arch_get_delegate_invoke_impls (void)
605 get_delegate_invoke_impl (&info
, TRUE
, 0);
606 res
= g_slist_prepend (res
, info
);
608 for (i
= 0; i
<= MAX_ARCH_DELEGATE_PARAMS
; ++i
) {
609 get_delegate_invoke_impl (&info
, FALSE
, i
);
610 res
= g_slist_prepend (res
, info
);
617 mono_arch_get_delegate_invoke_impl (MonoMethodSignature
*sig
, gboolean has_target
)
619 guint8
*code
, *start
;
621 /* FIXME: Support more cases */
622 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
626 static guint8
* cached
= NULL
;
627 mono_mini_arch_lock ();
629 mono_mini_arch_unlock ();
634 start
= mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
637 start
= get_delegate_invoke_impl (&info
, TRUE
, 0);
638 mono_tramp_info_register (info
, NULL
);
641 mono_mini_arch_unlock ();
644 static guint8
* cache
[MAX_ARCH_DELEGATE_PARAMS
+ 1] = {NULL
};
647 if (sig
->param_count
> MAX_ARCH_DELEGATE_PARAMS
)
649 for (i
= 0; i
< sig
->param_count
; ++i
)
650 if (!mono_is_regsize_var (sig
->params
[i
]))
653 mono_mini_arch_lock ();
654 code
= cache
[sig
->param_count
];
656 mono_mini_arch_unlock ();
661 char *name
= g_strdup_printf ("delegate_invoke_impl_target_%d", sig
->param_count
);
662 start
= mono_aot_get_trampoline (name
);
666 start
= get_delegate_invoke_impl (&info
, FALSE
, sig
->param_count
);
667 mono_tramp_info_register (info
, NULL
);
669 cache
[sig
->param_count
] = start
;
670 mono_mini_arch_unlock ();
678 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
, int offset
, gboolean load_imt_reg
)
684 mono_arch_get_this_arg_from_call (mgreg_t
*regs
, guint8
*code
)
687 return (gpointer
)regs
[mips_a0
];
691 * Initialize the cpu to execute managed code.
694 mono_arch_cpu_init (void)
696 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
705 ls_word_offset
= ls_word_idx
* 4;
706 ms_word_offset
= ms_word_idx
* 4;
710 * Initialize architecture specific code.
713 mono_arch_init (void)
715 mono_os_mutex_init_recursive (&mini_arch_mutex
);
717 ss_trigger_page
= mono_valloc (NULL
, mono_pagesize (), MONO_MMAP_READ
|MONO_MMAP_32BIT
, MONO_MEM_ACCOUNT_OTHER
);
718 bp_trigger_page
= mono_valloc (NULL
, mono_pagesize (), MONO_MMAP_READ
|MONO_MMAP_32BIT
, MONO_MEM_ACCOUNT_OTHER
);
719 mono_mprotect (bp_trigger_page
, mono_pagesize (), 0);
723 * Cleanup architecture specific code.
726 mono_arch_cleanup (void)
728 mono_os_mutex_destroy (&mini_arch_mutex
);
732 * This function returns the optimizations supported on this cpu.
735 mono_arch_cpu_optimizations (guint32
*exclude_mask
)
739 /* no mips-specific optimizations yet */
745 * This function test for all SIMD functions supported.
747 * Returns a bitmask corresponding to all supported versions.
751 mono_arch_cpu_enumerate_simd_versions (void)
753 /* SIMD is currently unimplemented */
758 mono_arch_get_allocatable_int_vars (MonoCompile
*cfg
)
763 for (i
= 0; i
< cfg
->num_varinfo
; i
++) {
764 MonoInst
*ins
= cfg
->varinfo
[i
];
765 MonoMethodVar
*vmv
= MONO_VARINFO (cfg
, i
);
768 if (vmv
->range
.first_use
.abs_pos
>= vmv
->range
.last_use
.abs_pos
)
771 if (ins
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
) || (ins
->opcode
!= OP_LOCAL
&& ins
->opcode
!= OP_ARG
))
774 /* we can only allocate 32 bit values */
775 if (mono_is_regsize_var (ins
->inst_vtype
)) {
776 g_assert (MONO_VARINFO (cfg
, i
)->reg
== -1);
777 g_assert (i
== vmv
->idx
);
778 vars
= mono_varlist_insert_sorted (cfg
, vars
, vmv
, FALSE
);
786 mono_arch_get_global_int_regs (MonoCompile
*cfg
)
790 regs
= g_list_prepend (regs
, (gpointer
)mips_s0
);
791 regs
= g_list_prepend (regs
, (gpointer
)mips_s1
);
792 regs
= g_list_prepend (regs
, (gpointer
)mips_s2
);
793 regs
= g_list_prepend (regs
, (gpointer
)mips_s3
);
794 regs
= g_list_prepend (regs
, (gpointer
)mips_s4
);
795 //regs = g_list_prepend (regs, (gpointer)mips_s5);
796 regs
= g_list_prepend (regs
, (gpointer
)mips_s6
);
797 regs
= g_list_prepend (regs
, (gpointer
)mips_s7
);
803 * mono_arch_regalloc_cost:
805 * Return the cost, in number of memory references, of the action of
806 * allocating the variable VMV into a register during global register
810 mono_arch_regalloc_cost (MonoCompile
*cfg
, MonoMethodVar
*vmv
)
817 args_onto_stack (CallInfo
*info
)
819 g_assert (!info
->on_stack
);
820 g_assert (info
->stack_size
<= MIPS_STACK_PARAM_OFFSET
);
821 info
->on_stack
= TRUE
;
822 info
->stack_size
= MIPS_STACK_PARAM_OFFSET
;
825 #if _MIPS_SIM == _ABIO32
827 * O32 calling convention version
831 add_int32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
832 /* First, see if we need to drop onto the stack */
833 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
834 args_onto_stack (info
);
836 /* Now, place the argument */
837 if (info
->on_stack
) {
838 ainfo
->storage
= ArgOnStack
;
839 ainfo
->reg
= mips_sp
; /* in the caller */
840 ainfo
->offset
= info
->stack_size
;
843 ainfo
->storage
= ArgInIReg
;
844 ainfo
->reg
= info
->gr
;
846 info
->gr_passed
= TRUE
;
848 info
->stack_size
+= 4;
852 add_int64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
853 /* First, see if we need to drop onto the stack */
854 if (!info
->on_stack
&& info
->gr
+1 > MIPS_LAST_ARG_REG
)
855 args_onto_stack (info
);
857 /* Now, place the argument */
858 if (info
->on_stack
) {
859 g_assert (info
->stack_size
% 4 == 0);
860 info
->stack_size
+= (info
->stack_size
% 8);
862 ainfo
->storage
= ArgOnStack
;
863 ainfo
->reg
= mips_sp
; /* in the caller */
864 ainfo
->offset
= info
->stack_size
;
867 // info->gr must be a0 or a2
868 info
->gr
+= (info
->gr
- MIPS_FIRST_ARG_REG
) % 2;
869 g_assert(info
->gr
<= MIPS_LAST_ARG_REG
);
871 ainfo
->storage
= ArgInIReg
;
872 ainfo
->reg
= info
->gr
;
874 info
->gr_passed
= TRUE
;
876 info
->stack_size
+= 8;
880 add_float32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
881 /* First, see if we need to drop onto the stack */
882 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
883 args_onto_stack (info
);
885 /* Now, place the argument */
886 if (info
->on_stack
) {
887 ainfo
->storage
= ArgOnStack
;
888 ainfo
->reg
= mips_sp
; /* in the caller */
889 ainfo
->offset
= info
->stack_size
;
892 /* Only use FP regs for args if no int args passed yet */
893 if (!info
->gr_passed
&& info
->fr
<= MIPS_LAST_FPARG_REG
) {
894 ainfo
->storage
= ArgInFReg
;
895 ainfo
->reg
= info
->fr
;
896 /* Even though it's a single-precision float, it takes up two FP regs */
898 /* FP and GP slots do not overlap */
902 /* Passing single-precision float arg in a GP register
903 * such as: func (0, 1.0, 2, 3);
904 * In this case, only one 'gr' register is consumed.
906 ainfo
->storage
= ArgInIReg
;
907 ainfo
->reg
= info
->gr
;
910 info
->gr_passed
= TRUE
;
913 info
->stack_size
+= 4;
917 add_float64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
918 /* First, see if we need to drop onto the stack */
919 if (!info
->on_stack
&& info
->gr
+1 > MIPS_LAST_ARG_REG
)
920 args_onto_stack (info
);
922 /* Now, place the argument */
923 if (info
->on_stack
) {
924 g_assert(info
->stack_size
% 4 == 0);
925 info
->stack_size
+= (info
->stack_size
% 8);
927 ainfo
->storage
= ArgOnStack
;
928 ainfo
->reg
= mips_sp
; /* in the caller */
929 ainfo
->offset
= info
->stack_size
;
932 /* Only use FP regs for args if no int args passed yet */
933 if (!info
->gr_passed
&& info
->fr
<= MIPS_LAST_FPARG_REG
) {
934 ainfo
->storage
= ArgInFReg
;
935 ainfo
->reg
= info
->fr
;
937 /* FP and GP slots do not overlap */
941 // info->gr must be a0 or a2
942 info
->gr
+= (info
->gr
- MIPS_FIRST_ARG_REG
) % 2;
943 g_assert(info
->gr
<= MIPS_LAST_ARG_REG
);
945 ainfo
->storage
= ArgInIReg
;
946 ainfo
->reg
= info
->gr
;
948 info
->gr_passed
= TRUE
;
951 info
->stack_size
+= 8;
953 #elif _MIPS_SIM == _ABIN32
955 * N32 calling convention version
959 add_int32_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 ainfo
->storage
= ArgOnStack
;
967 ainfo
->reg
= mips_sp
; /* in the caller */
968 ainfo
->offset
= info
->stack_size
;
969 info
->stack_size
+= SIZEOF_REGISTER
;
972 ainfo
->storage
= ArgInIReg
;
973 ainfo
->reg
= info
->gr
;
975 info
->gr_passed
= TRUE
;
980 add_int64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
981 /* First, see if we need to drop onto the stack */
982 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
983 args_onto_stack (info
);
985 /* Now, place the argument */
986 if (info
->on_stack
) {
987 g_assert (info
->stack_size
% 4 == 0);
988 info
->stack_size
+= (info
->stack_size
% 8);
990 ainfo
->storage
= ArgOnStack
;
991 ainfo
->reg
= mips_sp
; /* in the caller */
992 ainfo
->offset
= info
->stack_size
;
993 info
->stack_size
+= SIZEOF_REGISTER
;
996 g_assert (info
->gr
<= MIPS_LAST_ARG_REG
);
998 ainfo
->storage
= ArgInIReg
;
999 ainfo
->reg
= info
->gr
;
1001 info
->gr_passed
= TRUE
;
1006 add_float32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
1007 /* First, see if we need to drop onto the stack */
1008 if (!info
->on_stack
) {
1009 if (info
->gr
> MIPS_LAST_ARG_REG
)
1010 args_onto_stack (info
);
1011 else if (info
->fr
> MIPS_LAST_FPARG_REG
)
1012 args_onto_stack (info
);
1015 /* Now, place the argument */
1016 if (info
->on_stack
) {
1017 ainfo
->storage
= ArgOnStack
;
1018 ainfo
->reg
= mips_sp
; /* in the caller */
1019 ainfo
->offset
= info
->stack_size
;
1020 info
->stack_size
+= FREG_SIZE
;
1023 ainfo
->storage
= ArgInFReg
;
1024 ainfo
->reg
= info
->fr
;
1026 /* FP and GP slots do not overlap */
1032 add_float64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
1033 /* First, see if we need to drop onto the stack */
1034 if (!info
->on_stack
) {
1035 if (info
->gr
> MIPS_LAST_ARG_REG
)
1036 args_onto_stack (info
);
1037 else if (info
->fr
> MIPS_LAST_FPARG_REG
)
1038 args_onto_stack (info
);
1041 /* Now, place the argument */
1042 if (info
->on_stack
) {
1043 g_assert(info
->stack_size
% 4 == 0);
1044 info
->stack_size
+= (info
->stack_size
% 8);
1046 ainfo
->storage
= ArgOnStack
;
1047 ainfo
->reg
= mips_sp
; /* in the caller */
1048 ainfo
->offset
= info
->stack_size
;
1049 info
->stack_size
+= FREG_SIZE
;
1052 ainfo
->storage
= ArgInFReg
;
1053 ainfo
->reg
= info
->fr
;
1055 /* FP and GP slots do not overlap */
1062 get_call_info (MonoMemPool
*mp
, MonoMethodSignature
*sig
)
1065 int n
= sig
->hasthis
+ sig
->param_count
;
1067 MonoType
* simpletype
;
1069 gboolean is_pinvoke
= sig
->pinvoke
;
1072 cinfo
= mono_mempool_alloc0 (mp
, sizeof (CallInfo
) + (sizeof (ArgInfo
) * n
));
1074 cinfo
= g_malloc0 (sizeof (CallInfo
) + (sizeof (ArgInfo
) * n
));
1076 cinfo
->fr
= MIPS_FIRST_FPARG_REG
;
1077 cinfo
->gr
= MIPS_FIRST_ARG_REG
;
1078 cinfo
->stack_size
= 0;
1080 DEBUG(printf("calculate_sizes\n"));
1082 cinfo
->vtype_retaddr
= MONO_TYPE_ISSTRUCT (sig
->ret
) ? TRUE
: FALSE
;
1086 /* handle returning a struct */
1087 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1088 cinfo
->struct_ret
= cinfo
->gr
;
1089 add_int32_arg (cinfo
, &cinfo
->ret
);
1093 add_int32_arg (cinfo
, cinfo
->args
+ n
);
1098 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1099 * the first argument, allowing 'this' to be always passed in the first arg reg.
1100 * Also do this if the first argument is a reference type, since virtual calls
1101 * are sometimes made using calli without sig->hasthis set, like in the delegate
1104 if (cinfo
->vtype_retaddr
&& !is_pinvoke
&& (sig
->hasthis
|| (sig
->param_count
> 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig
->params
[0]))))) {
1106 add_int32_arg (cinfo
, cinfo
->args
+ n
);
1109 add_int32_arg (cinfo
, cinfo
->args
+ sig
->hasthis
);
1113 add_int32_arg (cinfo
, &cinfo
->ret
);
1114 cinfo
->struct_ret
= cinfo
->ret
.reg
;
1118 add_int32_arg (cinfo
, cinfo
->args
+ n
);
1122 if (cinfo
->vtype_retaddr
) {
1123 add_int32_arg (cinfo
, &cinfo
->ret
);
1124 cinfo
->struct_ret
= cinfo
->ret
.reg
;
1129 DEBUG(printf("params: %d\n", sig
->param_count
));
1130 for (i
= pstart
; i
< sig
->param_count
; ++i
) {
1131 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1132 /* Prevent implicit arguments and sig_cookie from
1133 being passed in registers */
1134 args_onto_stack (cinfo
);
1135 /* Emit the signature cookie just before the implicit arguments */
1136 add_int32_arg (cinfo
, &cinfo
->sig_cookie
);
1138 DEBUG(printf("param %d: ", i
));
1139 simpletype
= mini_get_underlying_type (sig
->params
[i
]);
1140 switch (simpletype
->type
) {
1141 case MONO_TYPE_BOOLEAN
:
1144 DEBUG(printf("1 byte\n"));
1145 cinfo
->args
[n
].size
= 1;
1146 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1149 case MONO_TYPE_CHAR
:
1152 DEBUG(printf("2 bytes\n"));
1153 cinfo
->args
[n
].size
= 2;
1154 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1159 DEBUG(printf("4 bytes\n"));
1160 cinfo
->args
[n
].size
= 4;
1161 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1167 case MONO_TYPE_FNPTR
:
1168 case MONO_TYPE_CLASS
:
1169 case MONO_TYPE_OBJECT
:
1170 case MONO_TYPE_STRING
:
1171 case MONO_TYPE_SZARRAY
:
1172 case MONO_TYPE_ARRAY
:
1173 cinfo
->args
[n
].size
= sizeof (gpointer
);
1174 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1177 case MONO_TYPE_GENERICINST
:
1178 if (!mono_type_generic_inst_is_valuetype (simpletype
)) {
1179 cinfo
->args
[n
].size
= sizeof (gpointer
);
1180 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1185 case MONO_TYPE_TYPEDBYREF
:
1186 case MONO_TYPE_VALUETYPE
: {
1189 int has_offset
= FALSE
;
1191 gint size
, alignment
;
1194 if (simpletype
->type
== MONO_TYPE_TYPEDBYREF
) {
1195 size
= sizeof (MonoTypedRef
);
1196 alignment
= sizeof (gpointer
);
1198 klass
= mono_class_from_mono_type (sig
->params
[i
]);
1200 size
= mono_class_native_size (klass
, NULL
);
1202 size
= mono_class_value_size (klass
, NULL
);
1203 alignment
= mono_class_min_align (klass
);
1205 #if MIPS_PASS_STRUCTS_BY_VALUE
1206 /* Need to do alignment if struct contains long or double */
1207 if (alignment
> 4) {
1208 /* Drop onto stack *before* looking at
1209 stack_size, if required. */
1210 if (!cinfo
->on_stack
&& cinfo
->gr
> MIPS_LAST_ARG_REG
)
1211 args_onto_stack (cinfo
);
1212 if (cinfo
->stack_size
& (alignment
- 1)) {
1213 add_int32_arg (cinfo
, &dummy_arg
);
1215 g_assert (!(cinfo
->stack_size
& (alignment
- 1)));
1219 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1220 mono_class_native_size (sig
->params
[i
]->data
.klass
, NULL
),
1221 cinfo
->stack_size
, alignment
);
1223 nwords
= (size
+ sizeof (gpointer
) -1 ) / sizeof (gpointer
);
1224 g_assert (cinfo
->args
[n
].size
== 0);
1225 g_assert (cinfo
->args
[n
].vtsize
== 0);
1226 for (j
= 0; j
< nwords
; ++j
) {
1228 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1229 if (cinfo
->on_stack
)
1232 add_int32_arg (cinfo
, &dummy_arg
);
1233 if (!has_offset
&& cinfo
->on_stack
) {
1234 cinfo
->args
[n
].offset
= dummy_arg
.offset
;
1238 if (cinfo
->on_stack
)
1239 cinfo
->args
[n
].vtsize
+= 1;
1241 cinfo
->args
[n
].size
+= 1;
1243 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1244 cinfo
->args
[n
].storage
= ArgStructByVal
;
1246 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1247 cinfo
->args
[n
].storage
= ArgStructByAddr
;
1254 DEBUG(printf("8 bytes\n"));
1255 cinfo
->args
[n
].size
= 8;
1256 add_int64_arg (cinfo
, &cinfo
->args
[n
]);
1260 DEBUG(printf("R4\n"));
1261 cinfo
->args
[n
].size
= 4;
1262 add_float32_arg (cinfo
, &cinfo
->args
[n
]);
1266 DEBUG(printf("R8\n"));
1267 cinfo
->args
[n
].size
= 8;
1268 add_float64_arg (cinfo
, &cinfo
->args
[n
]);
1272 g_error ("Can't trampoline 0x%x", sig
->params
[i
]->type
);
1276 /* Handle the case where there are no implicit arguments */
1277 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1278 /* Prevent implicit arguments and sig_cookie from
1279 being passed in registers */
1280 args_onto_stack (cinfo
);
1281 /* Emit the signature cookie just before the implicit arguments */
1282 add_int32_arg (cinfo
, &cinfo
->sig_cookie
);
1286 simpletype
= mini_get_underlying_type (sig
->ret
);
1287 switch (simpletype
->type
) {
1288 case MONO_TYPE_BOOLEAN
:
1293 case MONO_TYPE_CHAR
:
1299 case MONO_TYPE_FNPTR
:
1300 case MONO_TYPE_CLASS
:
1301 case MONO_TYPE_OBJECT
:
1302 case MONO_TYPE_SZARRAY
:
1303 case MONO_TYPE_ARRAY
:
1304 case MONO_TYPE_STRING
:
1305 cinfo
->ret
.reg
= mips_v0
;
1309 cinfo
->ret
.reg
= mips_v0
;
1313 cinfo
->ret
.reg
= mips_f0
;
1314 cinfo
->ret
.storage
= ArgInFReg
;
1316 case MONO_TYPE_GENERICINST
:
1317 if (!mono_type_generic_inst_is_valuetype (simpletype
)) {
1318 cinfo
->ret
.reg
= mips_v0
;
1322 case MONO_TYPE_VALUETYPE
:
1323 case MONO_TYPE_TYPEDBYREF
:
1325 case MONO_TYPE_VOID
:
1328 g_error ("Can't handle as return value 0x%x", sig
->ret
->type
);
1332 /* align stack size to 16 */
1333 cinfo
->stack_size
= (cinfo
->stack_size
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1335 cinfo
->stack_usage
= cinfo
->stack_size
;
1340 debug_omit_fp (void)
1343 return mono_debug_count ();
1350 * mono_arch_compute_omit_fp:
1352 * Determine whenever the frame pointer can be eliminated.
1355 mono_arch_compute_omit_fp (MonoCompile
*cfg
)
1357 MonoMethodSignature
*sig
;
1358 MonoMethodHeader
*header
;
1362 if (cfg
->arch
.omit_fp_computed
)
1365 header
= cfg
->header
;
1367 sig
= mono_method_signature (cfg
->method
);
1369 if (!cfg
->arch
.cinfo
)
1370 cfg
->arch
.cinfo
= get_call_info (cfg
->mempool
, sig
);
1371 cinfo
= cfg
->arch
.cinfo
;
1374 * FIXME: Remove some of the restrictions.
1376 cfg
->arch
.omit_fp
= TRUE
;
1377 cfg
->arch
.omit_fp_computed
= TRUE
;
1379 if (cfg
->disable_omit_fp
)
1380 cfg
->arch
.omit_fp
= FALSE
;
1381 if (!debug_omit_fp ())
1382 cfg
->arch
.omit_fp
= FALSE
;
1383 if (cfg
->method
->save_lmf
)
1384 cfg
->arch
.omit_fp
= FALSE
;
1385 if (cfg
->flags
& MONO_CFG_HAS_ALLOCA
)
1386 cfg
->arch
.omit_fp
= FALSE
;
1387 if (header
->num_clauses
)
1388 cfg
->arch
.omit_fp
= FALSE
;
1389 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
))
1390 cfg
->arch
.omit_fp
= FALSE
;
1391 if ((mono_jit_trace_calls
!= NULL
&& mono_trace_eval (cfg
->method
)) ||
1392 (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
))
1393 cfg
->arch
.omit_fp
= FALSE
;
1395 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1396 * there are stack arguments.
1399 if (cinfo->stack_usage)
1400 cfg->arch.omit_fp = FALSE;
1404 for (i
= cfg
->locals_start
; i
< cfg
->num_varinfo
; i
++) {
1405 MonoInst
*ins
= cfg
->varinfo
[i
];
1408 locals_size
+= mono_type_size (ins
->inst_vtype
, &ialign
);
1411 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1415 * Set var information according to the calling convention. mips version.
1416 * The locals var stuff should most likely be split in another method.
1419 mono_arch_allocate_vars (MonoCompile
*cfg
)
1421 MonoMethodSignature
*sig
;
1422 MonoMethodHeader
*header
;
1424 int i
, offset
, size
, align
, curinst
;
1425 int frame_reg
= mips_sp
;
1426 guint32 iregs_to_save
= 0;
1428 guint32 fregs_to_restore
;
1432 sig
= mono_method_signature (cfg
->method
);
1434 if (!cfg
->arch
.cinfo
)
1435 cfg
->arch
.cinfo
= get_call_info (cfg
->mempool
, sig
);
1436 cinfo
= cfg
->arch
.cinfo
;
1438 mono_arch_compute_omit_fp (cfg
);
1440 /* spill down, we'll fix it in a separate pass */
1441 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1443 /* allow room for the vararg method args: void* and long/double */
1444 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (cfg
->method
))
1445 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (gpointer
)*8);
1447 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1448 * call convs needs to be handled this way.
1450 if (cfg
->flags
& MONO_CFG_HAS_VARARGS
)
1451 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (gpointer
)*8);
1453 /* gtk-sharp and other broken code will dllimport vararg functions even with
1454 * non-varargs signatures. Since there is little hope people will get this right
1455 * we assume they won't.
1457 if (cfg
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
1458 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (gpointer
)*8);
1460 /* a0-a3 always present */
1461 cfg
->param_area
= MAX (cfg
->param_area
, MIPS_STACK_PARAM_OFFSET
);
1463 header
= cfg
->header
;
1465 if (cfg
->arch
.omit_fp
)
1466 frame_reg
= mips_sp
;
1468 frame_reg
= mips_fp
;
1469 cfg
->frame_reg
= frame_reg
;
1470 if (frame_reg
!= mips_sp
) {
1471 cfg
->used_int_regs
|= 1 << frame_reg
;
1476 if (!MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1477 /* FIXME: handle long and FP values */
1478 switch (mini_get_underlying_type (sig
->ret
)->type
) {
1479 case MONO_TYPE_VOID
:
1483 cfg
->ret
->opcode
= OP_REGVAR
;
1484 cfg
->ret
->inst_c0
= cfg
->ret
->dreg
= mips_f0
;
1487 cfg
->ret
->opcode
= OP_REGVAR
;
1488 cfg
->ret
->inst_c0
= mips_v0
;
1492 /* Space for outgoing parameters, including a0-a3 */
1493 offset
+= cfg
->param_area
;
1495 /* allow room to save the return value (if it's a struct) */
1496 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (cfg
->method
))
1499 /* Now handle the local variables */
1501 curinst
= cfg
->locals_start
;
1502 for (i
= curinst
; i
< cfg
->num_varinfo
; ++i
) {
1503 inst
= cfg
->varinfo
[i
];
1504 if ((inst
->flags
& MONO_INST_IS_DEAD
) || inst
->opcode
== OP_REGVAR
)
1507 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1508 * pinvoke wrappers when they call functions returning structure
1510 if (inst
->backend
.is_pinvoke
&& MONO_TYPE_ISSTRUCT (inst
->inst_vtype
) && inst
->inst_vtype
->type
!= MONO_TYPE_TYPEDBYREF
)
1511 size
= mono_class_native_size (mono_class_from_mono_type (inst
->inst_vtype
), (unsigned int *) &align
);
1513 size
= mono_type_size (inst
->inst_vtype
, &align
);
1515 offset
+= align
- 1;
1516 offset
&= ~(align
- 1);
1517 inst
->inst_offset
= offset
;
1518 inst
->opcode
= OP_REGOFFSET
;
1519 inst
->inst_basereg
= frame_reg
;
1521 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1524 /* Space for LMF (if needed) */
1525 if (cfg
->method
->save_lmf
) {
1526 /* align the offset to 16 bytes */
1527 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1528 cfg
->arch
.lmf_offset
= offset
;
1529 offset
+= sizeof (MonoLMF
);
1532 if (sig
->call_convention
== MONO_CALL_VARARG
) {
1536 /* Allocate a local slot to hold the sig cookie address */
1537 offset
+= align
- 1;
1538 offset
&= ~(align
- 1);
1539 cfg
->sig_cookie
= offset
;
1543 offset
+= SIZEOF_REGISTER
- 1;
1544 offset
&= ~(SIZEOF_REGISTER
- 1);
1546 /* Space for saved registers */
1547 cfg
->arch
.iregs_offset
= offset
;
1548 iregs_to_save
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
1549 if (iregs_to_save
) {
1550 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
1551 if (iregs_to_save
& (1 << i
)) {
1552 offset
+= SIZEOF_REGISTER
;
1557 /* saved float registers */
1559 fregs_to_restore
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
1560 if (fregs_to_restore
) {
1561 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
1562 if (fregs_to_restore
& (1 << i
)) {
1563 offset
+= sizeof(double);
1569 #if _MIPS_SIM == _ABIO32
1570 /* Now add space for saving the ra */
1571 offset
+= SIZEOF_VOID_P
;
1574 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1575 cfg
->stack_offset
= offset
;
1576 cfg
->arch
.local_alloc_offset
= cfg
->stack_offset
;
1580 * Now allocate stack slots for the int arg regs (a0 - a3)
1581 * On MIPS o32, these are just above the incoming stack pointer
1582 * Even if the arg has been assigned to a regvar, it gets a stack slot
1585 /* Return struct-by-value results in a hidden first argument */
1586 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1587 cfg
->vret_addr
->opcode
= OP_REGOFFSET
;
1588 cfg
->vret_addr
->inst_c0
= mips_a0
;
1589 cfg
->vret_addr
->inst_offset
= offset
;
1590 cfg
->vret_addr
->inst_basereg
= frame_reg
;
1591 offset
+= SIZEOF_REGISTER
;
1594 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
1595 inst
= cfg
->args
[i
];
1596 if (inst
->opcode
!= OP_REGVAR
) {
1599 if (sig
->hasthis
&& (i
== 0))
1600 arg_type
= &mono_defaults
.object_class
->byval_arg
;
1602 arg_type
= sig
->params
[i
- sig
->hasthis
];
1604 inst
->opcode
= OP_REGOFFSET
;
1605 size
= mono_type_size (arg_type
, &align
);
1607 if (size
< SIZEOF_REGISTER
) {
1608 size
= SIZEOF_REGISTER
;
1609 align
= SIZEOF_REGISTER
;
1611 inst
->inst_basereg
= frame_reg
;
1612 offset
= (offset
+ align
- 1) & ~(align
- 1);
1613 inst
->inst_offset
= offset
;
1615 if (cfg
->verbose_level
> 1)
1616 printf ("allocating param %d to fp[%d]\n", i
, inst
->inst_offset
);
1619 #if _MIPS_SIM == _ABIO32
1620 /* o32: Even a0-a3 get stack slots */
1621 size
= SIZEOF_REGISTER
;
1622 align
= SIZEOF_REGISTER
;
1623 inst
->inst_basereg
= frame_reg
;
1624 offset
= (offset
+ align
- 1) & ~(align
- 1);
1625 inst
->inst_offset
= offset
;
1627 if (cfg
->verbose_level
> 1)
1628 printf ("allocating param %d to fp[%d]\n", i
, inst
->inst_offset
);
1632 #if _MIPS_SIM == _ABIN32
1633 /* Now add space for saving the ra */
1634 offset
+= SIZEOF_VOID_P
;
1637 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1638 cfg
->stack_offset
= offset
;
1639 cfg
->arch
.local_alloc_offset
= cfg
->stack_offset
;
1644 mono_arch_create_vars (MonoCompile
*cfg
)
1646 MonoMethodSignature
*sig
;
1648 sig
= mono_method_signature (cfg
->method
);
1650 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1651 cfg
->vret_addr
= mono_compile_create_var (cfg
, &mono_defaults
.int_class
->byval_arg
, OP_ARG
);
1652 if (G_UNLIKELY (cfg
->verbose_level
> 1)) {
1653 printf ("vret_addr = ");
1654 mono_print_ins (cfg
->vret_addr
);
1659 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1660 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1664 * take the arguments and generate the arch-specific
1665 * instructions to properly call the function in call.
1666 * This includes pushing, moving arguments to the right register
1668 * Issue: who does the spilling if needed, and when?
1671 emit_sig_cookie (MonoCompile
*cfg
, MonoCallInst
*call
, CallInfo
*cinfo
)
1673 MonoMethodSignature
*tmp_sig
;
1676 if (call
->tail_call
)
1679 /* FIXME: Add support for signature tokens to AOT */
1680 cfg
->disable_aot
= TRUE
;
1683 * mono_ArgIterator_Setup assumes the signature cookie is
1684 * passed first and all the arguments which were before it are
1685 * passed on the stack after the signature. So compensate by
1686 * passing a different signature.
1688 tmp_sig
= mono_metadata_signature_dup (call
->signature
);
1689 tmp_sig
->param_count
-= call
->signature
->sentinelpos
;
1690 tmp_sig
->sentinelpos
= 0;
1691 memcpy (tmp_sig
->params
, call
->signature
->params
+ call
->signature
->sentinelpos
, tmp_sig
->param_count
* sizeof (MonoType
*));
1693 MONO_INST_NEW (cfg
, sig_arg
, OP_ICONST
);
1694 sig_arg
->dreg
= mono_alloc_ireg (cfg
);
1695 sig_arg
->inst_p0
= tmp_sig
;
1696 MONO_ADD_INS (cfg
->cbb
, sig_arg
);
1698 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_sp
, cinfo
->sig_cookie
.offset
, sig_arg
->dreg
);
1702 mono_arch_emit_call (MonoCompile
*cfg
, MonoCallInst
*call
)
1705 MonoMethodSignature
*sig
;
1710 sig
= call
->signature
;
1711 n
= sig
->param_count
+ sig
->hasthis
;
1713 cinfo
= get_call_info (cfg
->mempool
, sig
);
1714 if (cinfo
->struct_ret
)
1715 call
->used_iregs
|= 1 << cinfo
->struct_ret
;
1717 for (i
= 0; i
< n
; ++i
) {
1718 ArgInfo
*ainfo
= cinfo
->args
+ i
;
1721 if (i
>= sig
->hasthis
)
1722 t
= sig
->params
[i
- sig
->hasthis
];
1724 t
= &mono_defaults
.int_class
->byval_arg
;
1725 t
= mini_get_underlying_type (t
);
1727 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1728 /* Emit the signature cookie just before the implicit arguments */
1729 emit_sig_cookie (cfg
, call
, cinfo
);
1732 if (is_virtual
&& i
== 0) {
1733 /* the argument will be attached to the call instrucion */
1734 in
= call
->args
[i
];
1735 call
->used_iregs
|= 1 << ainfo
->reg
;
1738 in
= call
->args
[i
];
1739 if (ainfo
->storage
== ArgInIReg
) {
1740 #if SIZEOF_REGISTER == 4
1741 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1742 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1743 ins
->dreg
= mono_alloc_ireg (cfg
);
1744 ins
->sreg1
= MONO_LVREG_LS (in
->dreg
);
1745 MONO_ADD_INS (cfg
->cbb
, ins
);
1746 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
+ ls_word_idx
, FALSE
);
1748 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1749 ins
->dreg
= mono_alloc_ireg (cfg
);
1750 ins
->sreg1
= MONO_LVREG_MS (in
->dreg
);
1751 MONO_ADD_INS (cfg
->cbb
, ins
);
1752 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
+ ms_word_idx
, FALSE
);
1755 if (!t
->byref
&& (t
->type
== MONO_TYPE_R4
)) {
1758 #if PROMOTE_R4_TO_R8
1759 /* ??? - convert to single first? */
1760 MONO_INST_NEW (cfg
, ins
, OP_MIPS_CVTSD
);
1761 ins
->dreg
= mono_alloc_freg (cfg
);
1762 ins
->sreg1
= in
->dreg
;
1763 MONO_ADD_INS (cfg
->cbb
, ins
);
1768 /* trying to load float value into int registers */
1769 MONO_INST_NEW (cfg
, ins
, OP_MIPS_MFC1S
);
1770 ins
->dreg
= mono_alloc_ireg (cfg
);
1772 MONO_ADD_INS (cfg
->cbb
, ins
);
1773 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1774 } else if (!t
->byref
&& (t
->type
== MONO_TYPE_R8
)) {
1775 /* trying to load float value into int registers */
1776 MONO_INST_NEW (cfg
, ins
, OP_MIPS_MFC1D
);
1777 ins
->dreg
= mono_alloc_ireg (cfg
);
1778 ins
->sreg1
= in
->dreg
;
1779 MONO_ADD_INS (cfg
->cbb
, ins
);
1780 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1782 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1783 ins
->dreg
= mono_alloc_ireg (cfg
);
1784 ins
->sreg1
= in
->dreg
;
1785 MONO_ADD_INS (cfg
->cbb
, ins
);
1786 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1788 } else if (ainfo
->storage
== ArgStructByAddr
) {
1789 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1790 ins
->opcode
= OP_OUTARG_VT
;
1791 ins
->sreg1
= in
->dreg
;
1792 ins
->klass
= in
->klass
;
1793 ins
->inst_p0
= call
;
1794 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1795 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1796 MONO_ADD_INS (cfg
->cbb
, ins
);
1797 } else if (ainfo
->storage
== ArgStructByVal
) {
1798 /* this is further handled in mono_arch_emit_outarg_vt () */
1799 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1800 ins
->opcode
= OP_OUTARG_VT
;
1801 ins
->sreg1
= in
->dreg
;
1802 ins
->klass
= in
->klass
;
1803 ins
->inst_p0
= call
;
1804 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1805 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1806 MONO_ADD_INS (cfg
->cbb
, ins
);
1807 } else if (ainfo
->storage
== ArgOnStack
) {
1808 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1809 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1810 } else if (!t
->byref
&& ((t
->type
== MONO_TYPE_R4
) || (t
->type
== MONO_TYPE_R8
))) {
1811 if (t
->type
== MONO_TYPE_R8
)
1812 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER8_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1814 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER4_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1816 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1818 } else if (ainfo
->storage
== ArgInFReg
) {
1819 if (t
->type
== MONO_TYPE_VALUETYPE
) {
1820 /* this is further handled in mono_arch_emit_outarg_vt () */
1821 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1822 ins
->opcode
= OP_OUTARG_VT
;
1823 ins
->sreg1
= in
->dreg
;
1824 ins
->klass
= in
->klass
;
1825 ins
->inst_p0
= call
;
1826 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1827 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1828 MONO_ADD_INS (cfg
->cbb
, ins
);
1830 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1832 int dreg
= mono_alloc_freg (cfg
);
1834 if (ainfo
->size
== 4) {
1835 MONO_EMIT_NEW_UNALU (cfg
, OP_MIPS_CVTSD
, dreg
, in
->dreg
);
1837 MONO_INST_NEW (cfg
, ins
, OP_FMOVE
);
1839 ins
->sreg1
= in
->dreg
;
1840 MONO_ADD_INS (cfg
->cbb
, ins
);
1843 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1844 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1847 g_assert_not_reached ();
1851 /* Handle the case where there are no implicit arguments */
1852 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (n
== sig
->sentinelpos
))
1853 emit_sig_cookie (cfg
, call
, cinfo
);
1855 if (cinfo
->struct_ret
) {
1858 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
1859 vtarg
->sreg1
= call
->vret_var
->dreg
;
1860 vtarg
->dreg
= mono_alloc_preg (cfg
);
1861 MONO_ADD_INS (cfg
->cbb
, vtarg
);
1863 mono_call_inst_add_outarg_reg (cfg
, call
, vtarg
->dreg
, cinfo
->struct_ret
, FALSE
);
1867 * Reverse the call->out_args list.
1870 MonoInst
*prev
= NULL
, *list
= call
->out_args
, *next
;
1877 call
->out_args
= prev
;
1880 call
->stack_usage
= cinfo
->stack_usage
;
1881 cfg
->param_area
= MAX (cfg
->param_area
, cinfo
->stack_usage
);
1882 #if _MIPS_SIM == _ABIO32
1883 /* a0-a3 always present */
1884 cfg
->param_area
= MAX (cfg
->param_area
, 4 * SIZEOF_REGISTER
);
1886 cfg
->param_area
= (cfg
->param_area
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1887 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
1889 * should set more info in call, such as the stack space
1890 * used by the args that needs to be added back to esp
1895 mono_arch_emit_outarg_vt (MonoCompile
*cfg
, MonoInst
*ins
, MonoInst
*src
)
1897 MonoCallInst
*call
= (MonoCallInst
*)ins
->inst_p0
;
1898 ArgInfo
*ainfo
= ins
->inst_p1
;
1899 int ovf_size
= ainfo
->vtsize
;
1900 int doffset
= ainfo
->offset
;
1901 int i
, soffset
, dreg
;
1903 if (ainfo
->storage
== ArgStructByVal
) {
1905 if (cfg
->verbose_level
> 0) {
1906 char* nm
= mono_method_full_name (cfg
->method
, TRUE
);
1907 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1908 nm
, doffset
, ainfo
->size
, ovf_size
);
1914 for (i
= 0; i
< ainfo
->size
; ++i
) {
1915 dreg
= mono_alloc_ireg (cfg
);
1916 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, dreg
, src
->dreg
, soffset
);
1917 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
+ i
, FALSE
);
1918 soffset
+= SIZEOF_REGISTER
;
1920 if (ovf_size
!= 0) {
1921 mini_emit_memcpy (cfg
, mips_sp
, doffset
, src
->dreg
, soffset
, ovf_size
* sizeof (gpointer
), 0);
1923 } else if (ainfo
->storage
== ArgInFReg
) {
1924 int tmpr
= mono_alloc_freg (cfg
);
1926 if (ainfo
->size
== 4)
1927 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR4_MEMBASE
, tmpr
, src
->dreg
, 0);
1929 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR8_MEMBASE
, tmpr
, src
->dreg
, 0);
1930 dreg
= mono_alloc_freg (cfg
);
1931 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, dreg
, tmpr
);
1932 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1934 MonoInst
*vtcopy
= mono_compile_create_var (cfg
, &src
->klass
->byval_arg
, OP_LOCAL
);
1938 /* FIXME: alignment? */
1939 if (call
->signature
->pinvoke
) {
1940 size
= mono_type_native_stack_size (&src
->klass
->byval_arg
, NULL
);
1941 vtcopy
->backend
.is_pinvoke
= 1;
1943 size
= mini_type_stack_size (&src
->klass
->byval_arg
, NULL
);
1946 g_assert (ovf_size
> 0);
1948 EMIT_NEW_VARLOADA (cfg
, load
, vtcopy
, vtcopy
->inst_vtype
);
1949 mini_emit_memcpy (cfg
, load
->dreg
, 0, src
->dreg
, 0, size
, 0);
1952 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_at
, ainfo
->offset
, load
->dreg
);
1954 mono_call_inst_add_outarg_reg (cfg
, call
, load
->dreg
, ainfo
->reg
, FALSE
);
1959 mono_arch_emit_setret (MonoCompile
*cfg
, MonoMethod
*method
, MonoInst
*val
)
1961 MonoType
*ret
= mini_get_underlying_type (mono_method_signature (method
)->ret
);
1964 #if (SIZEOF_REGISTER == 4)
1965 if (ret
->type
== MONO_TYPE_I8
|| ret
->type
== MONO_TYPE_U8
) {
1968 MONO_INST_NEW (cfg
, ins
, OP_SETLRET
);
1969 ins
->sreg1
= MONO_LVREG_LS (val
->dreg
);
1970 ins
->sreg2
= MONO_LVREG_MS (val
->dreg
);
1971 MONO_ADD_INS (cfg
->cbb
, ins
);
1975 if (ret
->type
== MONO_TYPE_R8
) {
1976 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, cfg
->ret
->dreg
, val
->dreg
);
1979 if (ret
->type
== MONO_TYPE_R4
) {
1980 MONO_EMIT_NEW_UNALU (cfg
, OP_MIPS_CVTSD
, cfg
->ret
->dreg
, val
->dreg
);
1984 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, cfg
->ret
->dreg
, val
->dreg
);
1988 mono_arch_peephole_pass_1 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1990 MonoInst
*ins
, *n
, *last_ins
= NULL
;
1992 if (cfg
->verbose_level
> 2)
1993 g_print ("Basic block %d peephole pass 1\n", bb
->block_num
);
1996 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
1997 if (cfg
->verbose_level
> 2)
1998 mono_print_ins_index (0, ins
);
2000 switch (ins
->opcode
) {
2002 case OP_LOAD_MEMBASE
:
2003 case OP_LOADI4_MEMBASE
:
2005 * OP_IADD reg2, reg1, const1
2006 * OP_LOAD_MEMBASE const2(reg2), reg3
2008 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
2010 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
)){
2011 int const1
= last_ins
->inst_imm
;
2012 int const2
= ins
->inst_offset
;
2014 if (mips_is_imm16 (const1
+ const2
)) {
2015 ins
->inst_basereg
= last_ins
->sreg1
;
2016 ins
->inst_offset
= const1
+ const2
;
2026 bb
->last_ins
= last_ins
;
2030 mono_arch_peephole_pass_2 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2032 MonoInst
*ins
, *n
, *last_ins
= NULL
;
2035 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
2036 MonoInst
*last_ins
= ins
->prev
;
2038 switch (ins
->opcode
) {
2040 /* remove unnecessary multiplication with 1 */
2041 if (ins
->inst_imm
== 1) {
2042 if (ins
->dreg
!= ins
->sreg1
) {
2043 ins
->opcode
= OP_MOVE
;
2045 MONO_DELETE_INS (bb
, ins
);
2049 int power2
= mono_is_power_of_two (ins
->inst_imm
);
2051 ins
->opcode
= OP_SHL_IMM
;
2052 ins
->inst_imm
= power2
;
2056 case OP_LOAD_MEMBASE
:
2057 case OP_LOADI4_MEMBASE
:
2059 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2060 * OP_LOAD_MEMBASE offset(basereg), reg
2062 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_REG
2063 || last_ins
->opcode
== OP_STORE_MEMBASE_REG
) &&
2064 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2065 ins
->inst_offset
== last_ins
->inst_offset
) {
2066 if (ins
->dreg
== last_ins
->sreg1
) {
2067 MONO_DELETE_INS (bb
, ins
);
2070 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2071 ins
->opcode
= OP_MOVE
;
2072 ins
->sreg1
= last_ins
->sreg1
;
2077 * Note: reg1 must be different from the basereg in the second load
2078 * OP_LOAD_MEMBASE offset(basereg), reg1
2079 * OP_LOAD_MEMBASE offset(basereg), reg2
2081 * OP_LOAD_MEMBASE offset(basereg), reg1
2082 * OP_MOVE reg1, reg2
2084 if (last_ins
&& (last_ins
->opcode
== OP_LOADI4_MEMBASE
2085 || last_ins
->opcode
== OP_LOAD_MEMBASE
) &&
2086 ins
->inst_basereg
!= last_ins
->dreg
&&
2087 ins
->inst_basereg
== last_ins
->inst_basereg
&&
2088 ins
->inst_offset
== last_ins
->inst_offset
) {
2090 if (ins
->dreg
== last_ins
->dreg
) {
2091 MONO_DELETE_INS (bb
, ins
);
2094 ins
->opcode
= OP_MOVE
;
2095 ins
->sreg1
= last_ins
->dreg
;
2098 //g_assert_not_reached ();
2103 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2104 * OP_LOAD_MEMBASE offset(basereg), reg
2106 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2107 * OP_ICONST reg, imm
2109 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_IMM
2110 || last_ins
->opcode
== OP_STORE_MEMBASE_IMM
) &&
2111 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2112 ins
->inst_offset
== last_ins
->inst_offset
) {
2113 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2114 ins
->opcode
= OP_ICONST
;
2115 ins
->inst_c0
= last_ins
->inst_imm
;
2116 g_assert_not_reached (); // check this rule
2121 case OP_LOADU1_MEMBASE
:
2122 case OP_LOADI1_MEMBASE
:
2123 if (last_ins
&& (last_ins
->opcode
== OP_STOREI1_MEMBASE_REG
) &&
2124 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2125 ins
->inst_offset
== last_ins
->inst_offset
) {
2126 ins
->opcode
= (ins
->opcode
== OP_LOADI1_MEMBASE
) ? OP_ICONV_TO_I1
: OP_ICONV_TO_U1
;
2127 ins
->sreg1
= last_ins
->sreg1
;
2130 case OP_LOADU2_MEMBASE
:
2131 case OP_LOADI2_MEMBASE
:
2132 if (last_ins
&& (last_ins
->opcode
== OP_STOREI2_MEMBASE_REG
) &&
2133 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2134 ins
->inst_offset
== last_ins
->inst_offset
) {
2135 ins
->opcode
= (ins
->opcode
== OP_LOADI2_MEMBASE
) ? OP_ICONV_TO_I2
: OP_ICONV_TO_U2
;
2136 ins
->sreg1
= last_ins
->sreg1
;
2139 case OP_ICONV_TO_I4
:
2140 case OP_ICONV_TO_U4
:
2142 ins
->opcode
= OP_MOVE
;
2146 if (ins
->dreg
== ins
->sreg1
) {
2147 MONO_DELETE_INS (bb
, ins
);
2151 * OP_MOVE sreg, dreg
2152 * OP_MOVE dreg, sreg
2154 if (last_ins
&& last_ins
->opcode
== OP_MOVE
&&
2155 ins
->sreg1
== last_ins
->dreg
&&
2156 ins
->dreg
== last_ins
->sreg1
) {
2157 MONO_DELETE_INS (bb
, ins
);
2165 bb
->last_ins
= last_ins
;
2169 mono_arch_decompose_long_opts (MonoCompile
*cfg
, MonoInst
*ins
)
2177 switch (ins
->opcode
) {
2179 tmp1
= mono_alloc_ireg (cfg
);
2180 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2181 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
2182 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2183 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2188 tmp1
= mono_alloc_ireg (cfg
);
2189 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, ins
->dreg
+1, ins
->sreg1
+1, ins
->inst_ls_word
);
2190 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
2191 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, ins
->dreg
+2, ins
->sreg1
+2, ins
->inst_ms_word
);
2192 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2197 tmp1
= mono_alloc_ireg (cfg
);
2198 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2199 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
2200 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2201 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2206 tmp1
= mono_alloc_ireg (cfg
);
2207 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, ins
->dreg
+1, ins
->sreg1
+1, ins
->inst_ls_word
);
2208 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
2209 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, ins
->dreg
+2, ins
->sreg1
+2, ins
->inst_ms_word
);
2210 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2215 tmp1
= mono_alloc_ireg (cfg
);
2216 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, mips_zero
, ins
->sreg1
+1);
2217 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, mips_zero
, ins
->dreg
+1);
2218 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, mips_zero
, ins
->sreg1
+2);
2219 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2224 tmp1
= mono_alloc_ireg (cfg
);
2225 tmp2
= mono_alloc_ireg (cfg
);
2226 tmp3
= mono_alloc_ireg (cfg
);
2227 tmp4
= mono_alloc_ireg (cfg
);
2228 tmp5
= mono_alloc_ireg (cfg
);
2230 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2232 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2233 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp5
, ins
->dreg
+1, ins
->sreg1
+1);
2235 /* add the high 32-bits, and add in the carry from the low 32-bits */
2236 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2237 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, tmp5
, ins
->dreg
+2);
2239 /* Overflow happens if
2240 * neg + neg = pos or
2242 * XOR of the high bits returns 0 if the signs match
2243 * XOR of that with the high bit of the result return 1 if overflow.
2246 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2247 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
+2, ins
->sreg2
+2);
2249 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2250 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->dreg
+2, ins
->sreg2
+2);
2251 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tmp2
, tmp2
);
2253 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2254 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tmp3
, tmp2
, tmp1
);
2255 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp4
, tmp3
, 31);
2257 /* Now, if (tmp4 == 0) then overflow */
2258 MONO_EMIT_NEW_COMPARE_EXC (cfg
, EQ
, tmp4
, mips_zero
, "OverflowException");
2262 case OP_LADD_OVF_UN
:
2263 tmp1
= mono_alloc_ireg (cfg
);
2264 tmp2
= mono_alloc_ireg (cfg
);
2266 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2267 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
2268 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2269 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, tmp1
, ins
->dreg
+2);
2270 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp2
, ins
->dreg
+2, ins
->sreg1
+2);
2271 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp2
, mips_zero
, "OverflowException");
2276 tmp1
= mono_alloc_ireg (cfg
);
2277 tmp2
= mono_alloc_ireg (cfg
);
2278 tmp3
= mono_alloc_ireg (cfg
);
2279 tmp4
= mono_alloc_ireg (cfg
);
2280 tmp5
= mono_alloc_ireg (cfg
);
2282 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2284 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp5
, ins
->sreg1
+1, ins
->dreg
+1);
2285 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2286 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp5
);
2288 /* Overflow happens if
2289 * neg - pos = pos or
2291 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2293 * tmp1 = (lhs ^ rhs)
2294 * tmp2 = (lhs ^ result)
2295 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2298 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
+2, ins
->sreg2
+2);
2299 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->sreg1
+2, ins
->dreg
+2);
2300 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tmp3
, tmp2
, tmp1
);
2301 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp4
, tmp3
, 31);
2303 /* Now, if (tmp4 == 1) then overflow */
2304 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp4
, mips_zero
, "OverflowException");
2308 case OP_LSUB_OVF_UN
:
2309 tmp1
= mono_alloc_ireg (cfg
);
2310 tmp2
= mono_alloc_ireg (cfg
);
2312 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2313 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
2314 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2315 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2317 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp2
, ins
->sreg1
+2, ins
->dreg
+2);
2318 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp2
, mips_zero
, "OverflowException");
2321 case OP_LCONV_TO_OVF_I4_2
:
2322 tmp1
= mono_alloc_ireg (cfg
);
2324 /* Overflows if reg2 != sign extension of reg1 */
2325 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp1
, ins
->sreg1
, 31);
2326 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, ins
->sreg2
, tmp1
, "OverflowException");
2327 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
2336 mono_arch_decompose_opts (MonoCompile
*cfg
, MonoInst
*ins
)
2344 switch (ins
->opcode
) {
2346 tmp1
= mono_alloc_ireg (cfg
);
2347 tmp2
= mono_alloc_ireg (cfg
);
2348 tmp3
= mono_alloc_ireg (cfg
);
2349 tmp4
= mono_alloc_ireg (cfg
);
2350 tmp5
= mono_alloc_ireg (cfg
);
2352 /* add the operands */
2354 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2356 /* Overflow happens if
2357 * neg + neg = pos or
2360 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2361 * XOR of the high bit returns 0 if the signs match
2362 * XOR of that with the high bit of the result return 1 if overflow.
2365 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2366 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
, ins
->sreg2
);
2368 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2369 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->dreg
, ins
->sreg2
);
2370 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tmp3
, tmp2
);
2372 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2373 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tmp4
, tmp3
, tmp1
);
2375 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp5
, tmp4
, 31);
2377 /* Now, if (tmp5 == 0) then overflow */
2378 MONO_EMIT_NEW_COMPARE_EXC (cfg
, EQ
, 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_IADD_OVF_UN
:
2385 tmp1
= mono_alloc_ireg (cfg
);
2387 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2388 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
, ins
->sreg1
);
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
);
2396 tmp1
= mono_alloc_ireg (cfg
);
2397 tmp2
= mono_alloc_ireg (cfg
);
2398 tmp3
= mono_alloc_ireg (cfg
);
2399 tmp4
= mono_alloc_ireg (cfg
);
2400 tmp5
= mono_alloc_ireg (cfg
);
2402 /* add the operands */
2404 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2406 /* Overflow happens if
2407 * neg - pos = pos or
2409 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2411 * tmp1 = (lhs ^ rhs)
2412 * tmp2 = (lhs ^ result)
2413 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2416 /* tmp3 = 1 if the signs of the two inputs differ */
2417 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
, ins
->sreg2
);
2418 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->sreg1
, ins
->dreg
);
2419 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_MIPS_SLTI
, tmp3
, tmp1
, 0);
2420 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_MIPS_SLTI
, tmp4
, tmp2
, 0);
2421 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tmp5
, tmp4
, tmp3
);
2423 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp5
, mips_zero
, "OverflowException");
2424 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2425 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->dreg
);
2429 case OP_ISUB_OVF_UN
:
2430 tmp1
= mono_alloc_ireg (cfg
);
2432 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2433 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
, ins
->dreg
);
2434 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp1
, mips_zero
, "OverflowException");
2435 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2436 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->dreg
);
2443 map_to_reg_reg_op (int op
)
2452 case OP_COMPARE_IMM
:
2454 case OP_ICOMPARE_IMM
:
2456 case OP_LCOMPARE_IMM
:
2472 case OP_LOAD_MEMBASE
:
2473 return OP_LOAD_MEMINDEX
;
2474 case OP_LOADI4_MEMBASE
:
2475 return OP_LOADI4_MEMINDEX
;
2476 case OP_LOADU4_MEMBASE
:
2477 return OP_LOADU4_MEMINDEX
;
2478 case OP_LOADU1_MEMBASE
:
2479 return OP_LOADU1_MEMINDEX
;
2480 case OP_LOADI2_MEMBASE
:
2481 return OP_LOADI2_MEMINDEX
;
2482 case OP_LOADU2_MEMBASE
:
2483 return OP_LOADU2_MEMINDEX
;
2484 case OP_LOADI1_MEMBASE
:
2485 return OP_LOADI1_MEMINDEX
;
2486 case OP_LOADR4_MEMBASE
:
2487 return OP_LOADR4_MEMINDEX
;
2488 case OP_LOADR8_MEMBASE
:
2489 return OP_LOADR8_MEMINDEX
;
2490 case OP_STOREI1_MEMBASE_REG
:
2491 return OP_STOREI1_MEMINDEX
;
2492 case OP_STOREI2_MEMBASE_REG
:
2493 return OP_STOREI2_MEMINDEX
;
2494 case OP_STOREI4_MEMBASE_REG
:
2495 return OP_STOREI4_MEMINDEX
;
2496 case OP_STORE_MEMBASE_REG
:
2497 return OP_STORE_MEMINDEX
;
2498 case OP_STORER4_MEMBASE_REG
:
2499 return OP_STORER4_MEMINDEX
;
2500 case OP_STORER8_MEMBASE_REG
:
2501 return OP_STORER8_MEMINDEX
;
2502 case OP_STORE_MEMBASE_IMM
:
2503 return OP_STORE_MEMBASE_REG
;
2504 case OP_STOREI1_MEMBASE_IMM
:
2505 return OP_STOREI1_MEMBASE_REG
;
2506 case OP_STOREI2_MEMBASE_IMM
:
2507 return OP_STOREI2_MEMBASE_REG
;
2508 case OP_STOREI4_MEMBASE_IMM
:
2509 return OP_STOREI4_MEMBASE_REG
;
2510 case OP_STOREI8_MEMBASE_IMM
:
2511 return OP_STOREI8_MEMBASE_REG
;
2513 if (mono_op_imm_to_op (op
) == -1)
2514 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op
));
2515 return mono_op_imm_to_op (op
);
2519 map_to_mips_op (int op
)
2523 return OP_MIPS_FBEQ
;
2525 return OP_MIPS_FBGE
;
2527 return OP_MIPS_FBGT
;
2529 return OP_MIPS_FBLE
;
2531 return OP_MIPS_FBLT
;
2533 return OP_MIPS_FBNE
;
2535 return OP_MIPS_FBGE_UN
;
2537 return OP_MIPS_FBGT_UN
;
2539 return OP_MIPS_FBLE_UN
;
2541 return OP_MIPS_FBLT_UN
;
2549 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op
), __FUNCTION__
);
2550 g_assert_not_reached ();
2554 #define NEW_INS(cfg,after,dest,op) do { \
2555 MONO_INST_NEW((cfg), (dest), (op)); \
2556 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2559 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2561 MONO_INST_NEW(cfg, temp, (op)); \
2562 mono_bblock_insert_after_ins (bb, (pos), temp); \
2563 temp->dreg = (_dreg); \
2564 temp->sreg1 = (_sreg1); \
2565 temp->sreg2 = (_sreg2); \
2569 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2571 MONO_INST_NEW(cfg, temp, (op)); \
2572 mono_bblock_insert_after_ins (bb, (pos), temp); \
2573 temp->dreg = (_dreg); \
2574 temp->sreg1 = (_sreg1); \
2575 temp->inst_c0 = (_imm); \
2580 * Remove from the instruction list the instructions that can't be
2581 * represented with very simple instructions with no register
2585 mono_arch_lowering_pass (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2587 MonoInst
*ins
, *next
, *temp
, *last_ins
= NULL
;
2591 if (cfg
->verbose_level
> 2) {
2594 g_print ("BASIC BLOCK %d (before lowering)\n", bb
->block_num
);
2595 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2596 mono_print_ins_index (idx
++, ins
);
2602 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2604 switch (ins
->opcode
) {
2609 /* Branch opts can eliminate the branch */
2610 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2616 case OP_COMPARE_IMM
:
2617 case OP_ICOMPARE_IMM
:
2618 case OP_LCOMPARE_IMM
:
2620 /* Branch opts can eliminate the branch */
2621 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2625 if (ins
->inst_imm
) {
2626 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2627 temp
->inst_c0
= ins
->inst_imm
;
2628 temp
->dreg
= mono_alloc_ireg (cfg
);
2629 ins
->sreg2
= temp
->dreg
;
2633 ins
->sreg2
= mips_zero
;
2635 if (ins
->opcode
== OP_COMPARE_IMM
)
2636 ins
->opcode
= OP_COMPARE
;
2637 else if (ins
->opcode
== OP_ICOMPARE_IMM
)
2638 ins
->opcode
= OP_ICOMPARE
;
2639 else if (ins
->opcode
== OP_LCOMPARE_IMM
)
2640 ins
->opcode
= OP_LCOMPARE
;
2643 case OP_IDIV_UN_IMM
:
2646 case OP_IREM_UN_IMM
:
2647 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2648 temp
->inst_c0
= ins
->inst_imm
;
2649 temp
->dreg
= mono_alloc_ireg (cfg
);
2650 ins
->sreg2
= temp
->dreg
;
2651 if (ins
->opcode
== OP_IDIV_IMM
)
2652 ins
->opcode
= OP_IDIV
;
2653 else if (ins
->opcode
== OP_IREM_IMM
)
2654 ins
->opcode
= OP_IREM
;
2655 else if (ins
->opcode
== OP_IDIV_UN_IMM
)
2656 ins
->opcode
= OP_IDIV_UN
;
2657 else if (ins
->opcode
== OP_IREM_UN_IMM
)
2658 ins
->opcode
= OP_IREM_UN
;
2660 /* handle rem separately */
2667 if ((ins
->inst_imm
& 0xffff0000) && (ins
->inst_imm
& 0xffff)) {
2668 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2669 temp
->inst_c0
= ins
->inst_imm
;
2670 temp
->dreg
= mono_alloc_ireg (cfg
);
2671 ins
->sreg2
= temp
->dreg
;
2672 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2682 /* unsigned 16 bit immediate */
2683 if (ins
->inst_imm
& 0xffff0000) {
2684 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2685 temp
->inst_c0
= ins
->inst_imm
;
2686 temp
->dreg
= mono_alloc_ireg (cfg
);
2687 ins
->sreg2
= temp
->dreg
;
2688 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2695 /* signed 16 bit immediate */
2696 if (!mips_is_imm16 (ins
->inst_imm
)) {
2697 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2698 temp
->inst_c0
= ins
->inst_imm
;
2699 temp
->dreg
= mono_alloc_ireg (cfg
);
2700 ins
->sreg2
= temp
->dreg
;
2701 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2707 if (!mips_is_imm16 (-ins
->inst_imm
)) {
2708 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2709 temp
->inst_c0
= ins
->inst_imm
;
2710 temp
->dreg
= mono_alloc_ireg (cfg
);
2711 ins
->sreg2
= temp
->dreg
;
2712 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2718 if (ins
->inst_imm
== 1) {
2719 ins
->opcode
= OP_MOVE
;
2722 if (ins
->inst_imm
== 0) {
2723 ins
->opcode
= OP_ICONST
;
2727 imm
= mono_is_power_of_two (ins
->inst_imm
);
2729 ins
->opcode
= OP_SHL_IMM
;
2730 ins
->inst_imm
= imm
;
2733 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2734 temp
->inst_c0
= ins
->inst_imm
;
2735 temp
->dreg
= mono_alloc_ireg (cfg
);
2736 ins
->sreg2
= temp
->dreg
;
2737 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2740 case OP_LOCALLOC_IMM
:
2741 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2742 temp
->inst_c0
= ins
->inst_imm
;
2743 temp
->dreg
= mono_alloc_ireg (cfg
);
2744 ins
->sreg1
= temp
->dreg
;
2745 ins
->opcode
= OP_LOCALLOC
;
2748 case OP_LOADR4_MEMBASE
:
2749 case OP_STORER4_MEMBASE_REG
:
2750 /* we can do two things: load the immed in a register
2751 * and use an indexed load, or see if the immed can be
2752 * represented as an ad_imm + a load with a smaller offset
2753 * that fits. We just do the first for now, optimize later.
2755 if (mips_is_imm16 (ins
->inst_offset
))
2757 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2758 temp
->inst_c0
= ins
->inst_offset
;
2759 temp
->dreg
= mono_alloc_ireg (cfg
);
2760 ins
->sreg2
= temp
->dreg
;
2761 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2764 case OP_STORE_MEMBASE_IMM
:
2765 case OP_STOREI1_MEMBASE_IMM
:
2766 case OP_STOREI2_MEMBASE_IMM
:
2767 case OP_STOREI4_MEMBASE_IMM
:
2768 case OP_STOREI8_MEMBASE_IMM
:
2769 if (!ins
->inst_imm
) {
2770 ins
->sreg1
= mips_zero
;
2771 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2774 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2775 temp
->inst_c0
= ins
->inst_imm
;
2776 temp
->dreg
= mono_alloc_ireg (cfg
);
2777 ins
->sreg1
= temp
->dreg
;
2778 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2780 goto loop_start
; /* make it handle the possibly big ins->inst_offset */
2786 /* Branch opts can eliminate the branch */
2787 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2794 * remap compare/branch and compare/set
2795 * to MIPS specific opcodes.
2797 next
->opcode
= map_to_mips_op (next
->opcode
);
2798 next
->sreg1
= ins
->sreg1
;
2799 next
->sreg2
= ins
->sreg2
;
2806 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2807 temp
->inst_c0
= (guint32
)ins
->inst_p0
;
2808 temp
->dreg
= mono_alloc_ireg (cfg
);
2809 ins
->inst_basereg
= temp
->dreg
;
2810 ins
->inst_offset
= 0;
2811 ins
->opcode
= ins
->opcode
== OP_R4CONST
? OP_LOADR4_MEMBASE
: OP_LOADR8_MEMBASE
;
2813 /* make it handle the possibly big ins->inst_offset
2814 * later optimize to use lis + load_membase
2819 g_assert (ins_is_compare(last_ins
));
2820 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->sreg1
, last_ins
->sreg2
);
2821 NULLIFY_INS(last_ins
);
2825 g_assert (ins_is_compare(last_ins
));
2826 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->sreg1
, last_ins
->sreg2
);
2827 NULLIFY_INS(last_ins
);
2831 g_assert (ins_is_compare(last_ins
));
2832 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2833 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2834 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2838 g_assert (ins_is_compare(last_ins
));
2839 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2840 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2841 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2845 g_assert (ins_is_compare(last_ins
));
2846 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2847 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2848 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2852 g_assert (ins_is_compare(last_ins
));
2853 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2854 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2855 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2859 g_assert (ins_is_compare(last_ins
));
2860 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2861 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2862 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2866 g_assert (ins_is_compare(last_ins
));
2867 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2868 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2869 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2873 g_assert (ins_is_compare(last_ins
));
2874 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2875 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2876 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2880 g_assert (ins_is_compare(last_ins
));
2881 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2882 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2883 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2888 g_assert (ins_is_compare(last_ins
));
2889 last_ins
->opcode
= OP_IXOR
;
2890 last_ins
->dreg
= mono_alloc_ireg(cfg
);
2891 INS_REWRITE_IMM(ins
, OP_MIPS_SLTIU
, last_ins
->dreg
, 1);
2896 INS_REWRITE(ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2897 NULLIFY_INS(last_ins
);
2903 INS_REWRITE(ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2904 NULLIFY_INS(last_ins
);
2909 g_assert (ins_is_compare(last_ins
));
2910 INS_REWRITE(ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2911 MONO_DELETE_INS(bb
, last_ins
);
2916 g_assert (ins_is_compare(last_ins
));
2917 INS_REWRITE(ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2918 MONO_DELETE_INS(bb
, last_ins
);
2921 case OP_COND_EXC_EQ
:
2922 case OP_COND_EXC_IEQ
:
2923 g_assert (ins_is_compare(last_ins
));
2924 INS_REWRITE(ins
, OP_MIPS_COND_EXC_EQ
, last_ins
->sreg1
, last_ins
->sreg2
);
2925 MONO_DELETE_INS(bb
, last_ins
);
2928 case OP_COND_EXC_GE
:
2929 case OP_COND_EXC_IGE
:
2930 g_assert (ins_is_compare(last_ins
));
2931 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GE
, last_ins
->sreg1
, last_ins
->sreg2
);
2932 MONO_DELETE_INS(bb
, last_ins
);
2935 case OP_COND_EXC_GT
:
2936 case OP_COND_EXC_IGT
:
2937 g_assert (ins_is_compare(last_ins
));
2938 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GT
, last_ins
->sreg1
, last_ins
->sreg2
);
2939 MONO_DELETE_INS(bb
, last_ins
);
2942 case OP_COND_EXC_LE
:
2943 case OP_COND_EXC_ILE
:
2944 g_assert (ins_is_compare(last_ins
));
2945 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LE
, last_ins
->sreg1
, last_ins
->sreg2
);
2946 MONO_DELETE_INS(bb
, last_ins
);
2949 case OP_COND_EXC_LT
:
2950 case OP_COND_EXC_ILT
:
2951 g_assert (ins_is_compare(last_ins
));
2952 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LT
, last_ins
->sreg1
, last_ins
->sreg2
);
2953 MONO_DELETE_INS(bb
, last_ins
);
2956 case OP_COND_EXC_NE_UN
:
2957 case OP_COND_EXC_INE_UN
:
2958 g_assert (ins_is_compare(last_ins
));
2959 INS_REWRITE(ins
, OP_MIPS_COND_EXC_NE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2960 MONO_DELETE_INS(bb
, last_ins
);
2963 case OP_COND_EXC_GE_UN
:
2964 case OP_COND_EXC_IGE_UN
:
2965 g_assert (ins_is_compare(last_ins
));
2966 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2967 MONO_DELETE_INS(bb
, last_ins
);
2970 case OP_COND_EXC_GT_UN
:
2971 case OP_COND_EXC_IGT_UN
:
2972 g_assert (ins_is_compare(last_ins
));
2973 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GT_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2974 MONO_DELETE_INS(bb
, last_ins
);
2977 case OP_COND_EXC_LE_UN
:
2978 case OP_COND_EXC_ILE_UN
:
2979 g_assert (ins_is_compare(last_ins
));
2980 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2981 MONO_DELETE_INS(bb
, last_ins
);
2984 case OP_COND_EXC_LT_UN
:
2985 case OP_COND_EXC_ILT_UN
:
2986 g_assert (ins_is_compare(last_ins
));
2987 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LT_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2988 MONO_DELETE_INS(bb
, last_ins
);
2991 case OP_COND_EXC_OV
:
2992 case OP_COND_EXC_IOV
: {
2993 int tmp1
, tmp2
, tmp3
, tmp4
, tmp5
;
2994 MonoInst
*pos
= last_ins
;
2996 /* Overflow happens if
2997 * neg + neg = pos or
3000 * (bit31s of operands match) AND (bit31 of operand
3001 * != bit31 of result)
3002 * XOR of the high bit returns 0 if the signs match
3003 * XOR of that with the high bit of the result return 1
3006 g_assert (last_ins
->opcode
== OP_IADC
);
3008 tmp1
= mono_alloc_ireg (cfg
);
3009 tmp2
= mono_alloc_ireg (cfg
);
3010 tmp3
= mono_alloc_ireg (cfg
);
3011 tmp4
= mono_alloc_ireg (cfg
);
3012 tmp5
= mono_alloc_ireg (cfg
);
3014 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3015 INS (pos
, OP_IXOR
, tmp1
, last_ins
->sreg1
, last_ins
->sreg2
);
3017 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3018 INS (pos
, OP_IXOR
, tmp2
, last_ins
->dreg
, last_ins
->sreg2
);
3019 INS (pos
, OP_INOT
, tmp3
, tmp2
, -1);
3021 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3022 INS (pos
, OP_IOR
, tmp4
, tmp3
, tmp1
);
3023 INS_IMM (pos
, OP_SHR_IMM
, tmp5
, tmp4
, 31);
3025 /* Now, if (tmp5 == 0) then overflow */
3026 INS_REWRITE(ins
, OP_MIPS_COND_EXC_EQ
, tmp5
, mips_zero
);
3031 case OP_COND_EXC_NO
:
3032 case OP_COND_EXC_INO
:
3033 g_assert_not_reached ();
3037 case OP_COND_EXC_IC
:
3038 g_assert_not_reached ();
3041 case OP_COND_EXC_NC
:
3042 case OP_COND_EXC_INC
:
3043 g_assert_not_reached ();
3049 bb
->last_ins
= last_ins
;
3050 bb
->max_vreg
= cfg
->next_vreg
;
3053 if (cfg
->verbose_level
> 2) {
3056 g_print ("BASIC BLOCK %d (after lowering)\n", bb
->block_num
);
3057 MONO_BB_FOR_EACH_INS (bb
, ins
) {
3058 mono_print_ins_index (idx
++, ins
);
3067 emit_float_to_int (MonoCompile
*cfg
, guchar
*code
, int dreg
, int sreg
, int size
, gboolean is_signed
)
3069 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3071 mips_truncwd (code
, mips_ftemp
, sreg
);
3073 mips_cvtwd (code
, mips_ftemp
, sreg
);
3075 mips_mfc1 (code
, dreg
, mips_ftemp
);
3078 mips_andi (code
, dreg
, dreg
, 0xff);
3079 else if (size
== 2) {
3080 mips_sll (code
, dreg
, dreg
, 16);
3081 mips_srl (code
, dreg
, dreg
, 16);
3085 mips_sll (code
, dreg
, dreg
, 24);
3086 mips_sra (code
, dreg
, dreg
, 24);
3088 else if (size
== 2) {
3089 mips_sll (code
, dreg
, dreg
, 16);
3090 mips_sra (code
, dreg
, dreg
, 16);
3097 * emit_load_volatile_arguments:
3099 * Load volatile arguments from the stack to the original input registers.
3100 * Required before a tail call.
3103 emit_load_volatile_arguments(MonoCompile
*cfg
, guint8
*code
)
3105 MonoMethod
*method
= cfg
->method
;
3106 MonoMethodSignature
*sig
;
3111 sig
= mono_method_signature (method
);
3113 if (!cfg
->arch
.cinfo
)
3114 cfg
->arch
.cinfo
= get_call_info (cfg
->mempool
, sig
);
3115 cinfo
= cfg
->arch
.cinfo
;
3117 if (cinfo
->struct_ret
) {
3118 ArgInfo
*ainfo
= &cinfo
->ret
;
3119 inst
= cfg
->vret_addr
;
3120 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3123 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
3124 ArgInfo
*ainfo
= cinfo
->args
+ i
;
3125 inst
= cfg
->args
[i
];
3126 if (inst
->opcode
== OP_REGVAR
) {
3127 if (ainfo
->storage
== ArgInIReg
)
3128 MIPS_MOVE (code
, ainfo
->reg
, inst
->dreg
);
3129 else if (ainfo
->storage
== ArgInFReg
)
3130 g_assert_not_reached();
3131 else if (ainfo
->storage
== ArgOnStack
) {
3134 g_assert_not_reached ();
3136 if (ainfo
->storage
== ArgInIReg
) {
3137 g_assert (mips_is_imm16 (inst
->inst_offset
));
3138 switch (ainfo
->size
) {
3140 mips_lb (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3143 mips_lh (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3147 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3150 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+ ls_word_offset
);
3151 mips_lw (code
, ainfo
->reg
+ 1, inst
->inst_basereg
, inst
->inst_offset
+ ms_word_offset
);
3154 g_assert_not_reached ();
3157 } else if (ainfo
->storage
== ArgOnStack
) {
3159 } else if (ainfo
->storage
== ArgInFReg
) {
3160 g_assert (mips_is_imm16 (inst
->inst_offset
));
3161 if (ainfo
->size
== 8) {
3162 #if _MIPS_SIM == _ABIO32
3163 mips_lwc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+ ls_word_offset
);
3164 mips_lwc1 (code
, ainfo
->reg
+1, inst
->inst_basereg
, inst
->inst_offset
+ ms_word_offset
);
3165 #elif _MIPS_SIM == _ABIN32
3166 mips_ldc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3169 else if (ainfo
->size
== 4)
3170 mips_lwc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3172 g_assert_not_reached ();
3173 } else if (ainfo
->storage
== ArgStructByVal
) {
3175 int doffset
= inst
->inst_offset
;
3177 g_assert (mips_is_imm16 (inst
->inst_offset
));
3178 g_assert (mips_is_imm16 (inst
->inst_offset
+ ainfo
->size
* sizeof (gpointer
)));
3179 for (i
= 0; i
< ainfo
->size
; ++i
) {
3180 mips_lw (code
, ainfo
->reg
+ i
, inst
->inst_basereg
, doffset
);
3181 doffset
+= SIZEOF_REGISTER
;
3183 } else if (ainfo
->storage
== ArgStructByAddr
) {
3184 g_assert (mips_is_imm16 (inst
->inst_offset
));
3185 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3187 g_assert_not_reached ();
3195 emit_reserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3197 int size
= cfg
->param_area
;
3199 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3200 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3205 ppc_lwz (code
, ppc_r0
, 0, ppc_sp
);
3206 if (ppc_is_imm16 (-size
)) {
3207 ppc_stwu (code
, ppc_r0
, -size
, ppc_sp
);
3209 ppc_load (code
, ppc_r12
, -size
);
3210 ppc_stwux (code
, ppc_r0
, ppc_sp
, ppc_r12
);
3217 emit_unreserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3219 int size
= cfg
->param_area
;
3221 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3222 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3227 ppc_lwz (code
, ppc_r0
, 0, ppc_sp
);
3228 if (ppc_is_imm16 (size
)) {
3229 ppc_stwu (code
, ppc_r0
, size
, ppc_sp
);
3231 ppc_load (code
, ppc_r12
, size
);
3232 ppc_stwux (code
, ppc_r0
, ppc_sp
, ppc_r12
);
3239 mono_arch_output_basic_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
3244 guint8
*code
= cfg
->native_code
+ cfg
->code_len
;
3245 MonoInst
*last_ins
= NULL
;
3246 guint last_offset
= 0;
3250 /* we don't align basic blocks of loops on mips */
3252 if (cfg
->verbose_level
> 2)
3253 g_print ("Basic block %d starting at offset 0x%x\n", bb
->block_num
, bb
->native_offset
);
3255 cpos
= bb
->max_offset
;
3258 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
) {
3259 MonoCoverageInfo
*cov
= mono_get_coverage_info (cfg
->method
);
3260 g_assert (!mono_compile_aot
);
3263 cov
->data
[bb
->dfn
].iloffset
= bb
->cil_code
- cfg
->cil_code
;
3264 /* this is not thread save, but good enough */
3265 /* fixme: howto handle overflows? */
3266 mips_load_const (code
, mips_at
, &cov
->data
[bb
->dfn
].count
);
3267 mips_lw (code
, mips_temp
, mips_at
, 0);
3268 mips_addiu (code
, mips_temp
, mips_temp
, 1);
3269 mips_sw (code
, mips_temp
, mips_at
, 0);
3272 MONO_BB_FOR_EACH_INS (bb
, ins
) {
3273 offset
= code
- cfg
->native_code
;
3275 max_len
= ((guint8
*)ins_get_spec (ins
->opcode
))[MONO_INST_LEN
];
3277 if (offset
> (cfg
->code_size
- max_len
- 16)) {
3278 cfg
->code_size
*= 2;
3279 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
3280 code
= cfg
->native_code
+ offset
;
3282 mono_debug_record_line_number (cfg
, ins
, offset
);
3283 if (cfg
->verbose_level
> 2) {
3284 g_print (" @ 0x%x\t", offset
);
3285 mono_print_ins_index (ins_cnt
++, ins
);
3287 /* Check for virtual regs that snuck by */
3288 g_assert ((ins
->dreg
>= -1) && (ins
->dreg
< 32));
3290 switch (ins
->opcode
) {
3291 case OP_RELAXED_NOP
:
3294 case OP_DUMMY_STORE
:
3295 case OP_NOT_REACHED
:
3298 case OP_IL_SEQ_POINT
:
3299 mono_add_seq_point (cfg
, bb
, ins
, code
- cfg
->native_code
);
3301 case OP_SEQ_POINT
: {
3302 if (ins
->flags
& MONO_INST_SINGLE_STEP_LOC
) {
3303 guint32 addr
= (guint32
)ss_trigger_page
;
3305 mips_load_const (code
, mips_t9
, addr
);
3306 mips_lw (code
, mips_t9
, mips_t9
, 0);
3309 mono_add_seq_point (cfg
, bb
, ins
, code
- cfg
->native_code
);
3312 * A placeholder for a possible breakpoint inserted by
3313 * mono_arch_set_breakpoint ().
3315 /* mips_load_const () + mips_lw */
3322 g_assert_not_reached();
3324 emit_tls_access (code
, ins
->dreg
, ins
->inst_offset
);
3328 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3329 mips_mflo (code
, ins
->dreg
);
3330 mips_mfhi (code
, ins
->dreg
+1);
3333 mips_multu (code
, ins
->sreg1
, ins
->sreg2
);
3334 mips_mflo (code
, ins
->dreg
);
3335 mips_mfhi (code
, ins
->dreg
+1);
3337 case OP_MEMORY_BARRIER
:
3338 mips_sync (code
, 0);
3340 case OP_STOREI1_MEMBASE_IMM
:
3341 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3342 if (mips_is_imm16 (ins
->inst_offset
)) {
3343 mips_sb (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3345 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3346 mips_sb (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3349 case OP_STOREI2_MEMBASE_IMM
:
3350 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3351 if (mips_is_imm16 (ins
->inst_offset
)) {
3352 mips_sh (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3354 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3355 mips_sh (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3358 case OP_STOREI8_MEMBASE_IMM
:
3359 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3360 if (mips_is_imm16 (ins
->inst_offset
)) {
3361 mips_sd (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3363 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3364 mips_sd (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3367 case OP_STORE_MEMBASE_IMM
:
3368 case OP_STOREI4_MEMBASE_IMM
:
3369 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3370 if (mips_is_imm16 (ins
->inst_offset
)) {
3371 mips_sw (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3373 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3374 mips_sw (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3377 case OP_STOREI1_MEMBASE_REG
:
3378 if (mips_is_imm16 (ins
->inst_offset
)) {
3379 mips_sb (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3381 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3382 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3383 mips_sb (code
, ins
->sreg1
, mips_at
, 0);
3386 case OP_STOREI2_MEMBASE_REG
:
3387 if (mips_is_imm16 (ins
->inst_offset
)) {
3388 mips_sh (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3390 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3391 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3392 mips_sh (code
, ins
->sreg1
, mips_at
, 0);
3395 case OP_STORE_MEMBASE_REG
:
3396 case OP_STOREI4_MEMBASE_REG
:
3397 if (mips_is_imm16 (ins
->inst_offset
)) {
3398 mips_sw (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3400 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3401 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3402 mips_sw (code
, ins
->sreg1
, mips_at
, 0);
3405 case OP_STOREI8_MEMBASE_REG
:
3406 if (mips_is_imm16 (ins
->inst_offset
)) {
3407 mips_sd (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3409 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3410 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3411 mips_sd (code
, ins
->sreg1
, mips_at
, 0);
3415 g_assert_not_reached ();
3416 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3417 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3419 case OP_LOADI8_MEMBASE
:
3420 if (mips_is_imm16 (ins
->inst_offset
)) {
3421 mips_ld (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3423 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3424 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3425 mips_ld (code
, ins
->dreg
, mips_at
, 0);
3428 case OP_LOAD_MEMBASE
:
3429 case OP_LOADI4_MEMBASE
:
3430 case OP_LOADU4_MEMBASE
:
3431 g_assert (ins
->dreg
!= -1);
3432 if (mips_is_imm16 (ins
->inst_offset
)) {
3433 mips_lw (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3435 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3436 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3437 mips_lw (code
, ins
->dreg
, mips_at
, 0);
3440 case OP_LOADI1_MEMBASE
:
3441 if (mips_is_imm16 (ins
->inst_offset
)) {
3442 mips_lb (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3444 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3445 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3446 mips_lb (code
, ins
->dreg
, mips_at
, 0);
3449 case OP_LOADU1_MEMBASE
:
3450 if (mips_is_imm16 (ins
->inst_offset
)) {
3451 mips_lbu (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3453 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3454 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3455 mips_lbu (code
, ins
->dreg
, mips_at
, 0);
3458 case OP_LOADI2_MEMBASE
:
3459 if (mips_is_imm16 (ins
->inst_offset
)) {
3460 mips_lh (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3462 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3463 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3464 mips_lh (code
, ins
->dreg
, mips_at
, 0);
3467 case OP_LOADU2_MEMBASE
:
3468 if (mips_is_imm16 (ins
->inst_offset
)) {
3469 mips_lhu (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3471 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3472 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3473 mips_lhu (code
, ins
->dreg
, mips_at
, 0);
3476 case OP_ICONV_TO_I1
:
3477 mips_sll (code
, mips_at
, ins
->sreg1
, 24);
3478 mips_sra (code
, ins
->dreg
, mips_at
, 24);
3480 case OP_ICONV_TO_I2
:
3481 mips_sll (code
, mips_at
, ins
->sreg1
, 16);
3482 mips_sra (code
, ins
->dreg
, mips_at
, 16);
3484 case OP_ICONV_TO_U1
:
3485 mips_andi (code
, ins
->dreg
, ins
->sreg1
, 0xff);
3487 case OP_ICONV_TO_U2
:
3488 mips_sll (code
, mips_at
, ins
->sreg1
, 16);
3489 mips_srl (code
, ins
->dreg
, mips_at
, 16);
3492 mips_slt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3495 g_assert (mips_is_imm16 (ins
->inst_imm
));
3496 mips_slti (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3499 mips_sltu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3502 g_assert (mips_is_imm16 (ins
->inst_imm
));
3503 mips_sltiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3507 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3508 * So instead of emitting a trap, we emit a call a C function and place a
3511 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_INTERNAL_METHOD
,
3512 (gpointer
)"mono_break");
3513 mips_load (code
, mips_t9
, 0x1f1f1f1f);
3514 mips_jalr (code
, mips_t9
, mips_ra
);
3518 mips_addu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3521 mips_daddu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3526 g_assert (mips_is_imm16 (ins
->inst_imm
));
3527 mips_addiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3530 g_assert (mips_is_imm16 (ins
->inst_imm
));
3531 mips_daddiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3535 mips_subu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3538 mips_dsubu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3543 // we add the negated value
3544 g_assert (mips_is_imm16 (-ins
->inst_imm
));
3545 mips_addiu (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
3549 // we add the negated value
3550 g_assert (mips_is_imm16 (-ins
->inst_imm
));
3551 mips_daddiu (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
3556 mips_and (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3562 g_assert (!(ins
->inst_imm
& 0xffff0000));
3563 mips_andi (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3568 guint32
*divisor_is_m1
;
3569 guint32
*dividend_is_minvalue
;
3570 guint32
*divisor_is_zero
;
3572 mips_load_const (code
, mips_at
, -1);
3573 divisor_is_m1
= (guint32
*)(void *)code
;
3574 mips_bne (code
, ins
->sreg2
, mips_at
, 0);
3575 mips_lui (code
, mips_at
, mips_zero
, 0x8000);
3576 dividend_is_minvalue
= (guint32
*)(void *)code
;
3577 mips_bne (code
, ins
->sreg1
, mips_at
, 0);
3580 /* Divide Int32.MinValue by -1 -- throw exception */
3581 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3583 mips_patch (divisor_is_m1
, (guint32
)code
);
3584 mips_patch (dividend_is_minvalue
, (guint32
)code
);
3586 /* Put divide in branch delay slot (NOT YET) */
3587 divisor_is_zero
= (guint32
*)(void *)code
;
3588 mips_bne (code
, ins
->sreg2
, mips_zero
, 0);
3591 /* Divide by zero -- throw exception */
3592 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3594 mips_patch (divisor_is_zero
, (guint32
)code
);
3595 mips_div (code
, ins
->sreg1
, ins
->sreg2
);
3596 if (ins
->opcode
== OP_IDIV
)
3597 mips_mflo (code
, ins
->dreg
);
3599 mips_mfhi (code
, ins
->dreg
);
3604 guint32
*divisor_is_zero
= (guint32
*)(void *)code
;
3606 /* Put divide in branch delay slot (NOT YET) */
3607 mips_bne (code
, ins
->sreg2
, mips_zero
, 0);
3610 /* Divide by zero -- throw exception */
3611 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3613 mips_patch (divisor_is_zero
, (guint32
)code
);
3614 mips_divu (code
, ins
->sreg1
, ins
->sreg2
);
3615 if (ins
->opcode
== OP_IDIV_UN
)
3616 mips_mflo (code
, ins
->dreg
);
3618 mips_mfhi (code
, ins
->dreg
);
3622 g_assert_not_reached ();
3624 ppc_load (code
, ppc_r12
, ins
->inst_imm
);
3625 ppc_divwod (code
, ins
->dreg
, ins
->sreg1
, ppc_r12
);
3626 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3627 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3628 /* FIXME: use OverflowException for 0x80000000/-1 */
3629 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
3631 g_assert_not_reached();
3634 g_assert_not_reached ();
3636 mips_or (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3640 g_assert (!(ins
->inst_imm
& 0xffff0000));
3641 mips_ori (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3644 mips_xor (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3648 /* unsigned 16-bit immediate */
3649 g_assert (!(ins
->inst_imm
& 0xffff0000));
3650 mips_xori (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3653 mips_sllv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3657 mips_sll (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3660 mips_srav (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3663 mips_dsrav (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3667 mips_sra (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3670 mips_dsra (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x3f);
3673 case OP_ISHR_UN_IMM
:
3674 mips_srl (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3676 case OP_LSHR_UN_IMM
:
3677 mips_dsrl (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x3f);
3680 mips_srlv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3683 mips_dsrlv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3687 mips_nor (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3690 mips_subu (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3693 mips_dsubu (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3697 mips_mul (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3699 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3700 mips_mflo (code
, ins
->dreg
);
3705 #if SIZEOF_REGISTER == 8
3707 mips_dmult (code
, ins
->sreg1
, ins
->sreg2
);
3708 mips_mflo (code
, ins
->dreg
);
3713 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3714 mips_mflo (code
, ins
->dreg
);
3715 mips_mfhi (code
, mips_at
);
3718 mips_sra (code
, mips_temp
, ins
->dreg
, 31);
3719 patch
= (guint32
*)(void *)code
;
3720 mips_beq (code
, mips_temp
, mips_at
, 0);
3722 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3723 mips_patch (patch
, (guint32
)code
);
3726 case OP_IMUL_OVF_UN
: {
3728 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3729 mips_mflo (code
, ins
->dreg
);
3730 mips_mfhi (code
, mips_at
);
3733 patch
= (guint32
*)(void *)code
;
3734 mips_beq (code
, mips_at
, mips_zero
, 0);
3736 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3737 mips_patch (patch
, (guint32
)code
);
3741 mips_load_const (code
, ins
->dreg
, ins
->inst_c0
);
3743 #if SIZEOF_REGISTER == 8
3745 mips_load_const (code
, ins
->dreg
, ins
->inst_c0
);
3749 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_i1
, ins
->inst_p0
);
3750 mips_load (code
, ins
->dreg
, 0);
3754 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3756 case OP_MIPS_MTC1S_2
:
3757 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3758 mips_mtc1 (code
, ins
->dreg
+1, ins
->sreg2
);
3761 mips_mfc1 (code
, ins
->dreg
, ins
->sreg1
);
3764 mips_dmtc1 (code
, ins
->dreg
, ins
->sreg1
);
3768 mips_dmfc1 (code
, ins
->dreg
, ins
->sreg1
);
3770 mips_mfc1 (code
, ins
->dreg
, ins
->sreg1
+ ls_word_idx
);
3771 mips_mfc1 (code
, ins
->dreg
+1, ins
->sreg1
+ ms_word_idx
);
3775 case OP_ICONV_TO_I4
:
3776 case OP_ICONV_TO_U4
:
3778 if (ins
->dreg
!= ins
->sreg1
)
3779 MIPS_MOVE (code
, ins
->dreg
, ins
->sreg1
);
3781 #if SIZEOF_REGISTER == 8
3783 mips_dsll (code
, ins
->dreg
, ins
->sreg1
, 32);
3784 mips_dsrl (code
, ins
->dreg
, ins
->dreg
, 32);
3787 mips_dsll (code
, ins
->dreg
, ins
->sreg1
, 32);
3788 mips_dsra (code
, ins
->dreg
, ins
->dreg
, 32);
3792 int lsreg
= mips_v0
+ ls_word_idx
;
3793 int msreg
= mips_v0
+ ms_word_idx
;
3795 /* Get sreg1 into lsreg, sreg2 into msreg */
3797 if (ins
->sreg1
== msreg
) {
3798 if (ins
->sreg1
!= mips_at
)
3799 MIPS_MOVE (code
, mips_at
, ins
->sreg1
);
3800 if (ins
->sreg2
!= msreg
)
3801 MIPS_MOVE (code
, msreg
, ins
->sreg2
);
3802 MIPS_MOVE (code
, lsreg
, mips_at
);
3805 if (ins
->sreg2
!= msreg
)
3806 MIPS_MOVE (code
, msreg
, ins
->sreg2
);
3807 if (ins
->sreg1
!= lsreg
)
3808 MIPS_MOVE (code
, lsreg
, ins
->sreg1
);
3813 if (ins
->dreg
!= ins
->sreg1
) {
3814 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
3817 case OP_MOVE_F_TO_I4
:
3818 mips_cvtsd (code
, mips_ftemp
, ins
->sreg1
);
3819 mips_mfc1 (code
, ins
->dreg
, mips_ftemp
);
3821 case OP_MOVE_I4_TO_F
:
3822 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3823 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
3826 /* Convert from double to float and leave it there */
3827 mips_cvtsd (code
, ins
->dreg
, ins
->sreg1
);
3829 case OP_FCONV_TO_R4
:
3831 mips_cvtsd (code
, ins
->dreg
, ins
->sreg1
);
3833 /* Just a move, no precision change */
3834 if (ins
->dreg
!= ins
->sreg1
) {
3835 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
3840 code
= emit_load_volatile_arguments(cfg
, code
);
3843 * Pop our stack, then jump to specified method (tail-call)
3844 * Keep in sync with mono_arch_emit_epilog
3846 code
= mono_arch_emit_epilog_sub (cfg
, code
);
3848 mono_add_patch_info (cfg
, (guint8
*) code
- cfg
->native_code
,
3849 MONO_PATCH_INFO_METHOD_JUMP
, ins
->inst_p0
);
3850 mips_load (code
, mips_t9
, 0);
3851 mips_jr (code
, mips_t9
);
3855 /* ensure ins->sreg1 is not NULL */
3856 mips_lw (code
, mips_zero
, ins
->sreg1
, 0);
3859 g_assert (mips_is_imm16 (cfg
->sig_cookie
));
3860 mips_lw (code
, mips_at
, cfg
->frame_reg
, cfg
->sig_cookie
);
3861 mips_sw (code
, mips_at
, ins
->sreg1
, 0);
3874 case OP_VOIDCALL_REG
:
3876 case OP_FCALL_MEMBASE
:
3877 case OP_LCALL_MEMBASE
:
3878 case OP_VCALL_MEMBASE
:
3879 case OP_VCALL2_MEMBASE
:
3880 case OP_VOIDCALL_MEMBASE
:
3881 case OP_CALL_MEMBASE
:
3882 call
= (MonoCallInst
*)ins
;
3883 switch (ins
->opcode
) {
3890 if (ins
->flags
& MONO_INST_HAS_METHOD
) {
3891 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_METHOD
, call
->method
);
3892 mips_load (code
, mips_t9
, call
->method
);
3895 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_ABS
, call
->fptr
);
3896 mips_load (code
, mips_t9
, call
->fptr
);
3898 mips_jalr (code
, mips_t9
, mips_ra
);
3905 case OP_VOIDCALL_REG
:
3907 MIPS_MOVE (code
, mips_t9
, ins
->sreg1
);
3908 mips_jalr (code
, mips_t9
, mips_ra
);
3911 case OP_FCALL_MEMBASE
:
3912 case OP_LCALL_MEMBASE
:
3913 case OP_VCALL_MEMBASE
:
3914 case OP_VCALL2_MEMBASE
:
3915 case OP_VOIDCALL_MEMBASE
:
3916 case OP_CALL_MEMBASE
:
3917 mips_lw (code
, mips_t9
, ins
->sreg1
, ins
->inst_offset
);
3918 mips_jalr (code
, mips_t9
, mips_ra
);
3922 #if PROMOTE_R4_TO_R8
3923 /* returned an FP R4 (single), promote to R8 (double) in place */
3924 switch (ins
->opcode
) {
3927 case OP_FCALL_MEMBASE
:
3928 if (call
->signature
->ret
->type
== MONO_TYPE_R4
)
3929 mips_cvtds (code
, mips_f0
, mips_f0
);
3937 int area_offset
= cfg
->param_area
;
3939 /* Round up ins->sreg1, mips_at ends up holding size */
3940 mips_addiu (code
, mips_at
, ins
->sreg1
, 31);
3941 mips_addiu (code
, mips_temp
, mips_zero
, ~31);
3942 mips_and (code
, mips_at
, mips_at
, mips_temp
);
3944 mips_subu (code
, mips_sp
, mips_sp
, mips_at
);
3945 g_assert (mips_is_imm16 (area_offset
));
3946 mips_addiu (code
, ins
->dreg
, mips_sp
, area_offset
);
3948 if (ins
->flags
& MONO_INST_INIT
) {
3951 buf
= (guint32
*)(void*)code
;
3952 mips_beq (code
, mips_at
, mips_zero
, 0);
3955 mips_move (code
, mips_temp
, ins
->dreg
);
3956 mips_sb (code
, mips_zero
, mips_temp
, 0);
3957 mips_addiu (code
, mips_at
, mips_at
, -1);
3958 mips_bne (code
, mips_at
, mips_zero
, -3);
3959 mips_addiu (code
, mips_temp
, mips_temp
, 1);
3961 mips_patch (buf
, (guint32
)code
);
3966 gpointer addr
= mono_arch_get_throw_exception(NULL
, FALSE
);
3967 mips_move (code
, mips_a0
, ins
->sreg1
);
3968 mips_call (code
, mips_t9
, addr
);
3969 mips_break (code
, 0xfc);
3973 gpointer addr
= mono_arch_get_rethrow_exception(NULL
, FALSE
);
3974 mips_move (code
, mips_a0
, ins
->sreg1
);
3975 mips_call (code
, mips_t9
, addr
);
3976 mips_break (code
, 0xfb);
3979 case OP_START_HANDLER
: {
3981 * The START_HANDLER instruction marks the beginning of
3982 * a handler block. It is called using a call
3983 * instruction, so mips_ra contains the return address.
3984 * Since the handler executes in the same stack frame
3985 * as the method itself, we can't use save/restore to
3986 * save the return address. Instead, we save it into
3987 * a dedicated variable.
3989 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3990 g_assert (spvar
->inst_basereg
!= mips_sp
);
3991 code
= emit_reserve_param_area (cfg
, code
);
3993 if (mips_is_imm16 (spvar
->inst_offset
)) {
3994 mips_sw (code
, mips_ra
, spvar
->inst_basereg
, spvar
->inst_offset
);
3996 mips_load_const (code
, mips_at
, spvar
->inst_offset
);
3997 mips_addu (code
, mips_at
, mips_at
, spvar
->inst_basereg
);
3998 mips_sw (code
, mips_ra
, mips_at
, 0);
4002 case OP_ENDFILTER
: {
4003 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
4004 g_assert (spvar
->inst_basereg
!= mips_sp
);
4005 code
= emit_unreserve_param_area (cfg
, code
);
4007 if (ins
->sreg1
!= mips_v0
)
4008 MIPS_MOVE (code
, mips_v0
, ins
->sreg1
);
4009 if (mips_is_imm16 (spvar
->inst_offset
)) {
4010 mips_lw (code
, mips_ra
, spvar
->inst_basereg
, spvar
->inst_offset
);
4012 mips_load_const (code
, mips_at
, spvar
->inst_offset
);
4013 mips_addu (code
, mips_at
, mips_at
, spvar
->inst_basereg
);
4014 mips_lw (code
, mips_ra
, mips_at
, 0);
4016 mips_jr (code
, mips_ra
);
4020 case OP_ENDFINALLY
: {
4021 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
4022 g_assert (spvar
->inst_basereg
!= mips_sp
);
4023 code
= emit_unreserve_param_area (cfg
, code
);
4024 mips_lw (code
, mips_t9
, spvar
->inst_basereg
, spvar
->inst_offset
);
4025 mips_jalr (code
, mips_t9
, mips_ra
);
4029 case OP_CALL_HANDLER
:
4030 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
4031 mips_lui (code
, mips_t9
, mips_zero
, 0);
4032 mips_addiu (code
, mips_t9
, mips_t9
, 0);
4033 mips_jalr (code
, mips_t9
, mips_ra
);
4035 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4036 mono_cfg_add_try_hole (cfg
, ins
->inst_eh_block
, code
, bb
);
4039 ins
->inst_c0
= code
- cfg
->native_code
;
4042 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
4043 if (cfg
->arch
.long_branch
) {
4044 mips_lui (code
, mips_at
, mips_zero
, 0);
4045 mips_addiu (code
, mips_at
, mips_at
, 0);
4046 mips_jr (code
, mips_at
);
4050 mips_beq (code
, mips_zero
, mips_zero
, 0);
4055 mips_jr (code
, ins
->sreg1
);
4061 max_len
+= 4 * GPOINTER_TO_INT (ins
->klass
);
4062 if (offset
> (cfg
->code_size
- max_len
- 16)) {
4063 cfg
->code_size
+= max_len
;
4064 cfg
->code_size
*= 2;
4065 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
4066 code
= cfg
->native_code
+ offset
;
4068 g_assert (ins
->sreg1
!= -1);
4069 mips_sll (code
, mips_at
, ins
->sreg1
, 2);
4070 if (1 || !(cfg
->flags
& MONO_CFG_HAS_CALLS
))
4071 MIPS_MOVE (code
, mips_t8
, mips_ra
);
4072 mips_bgezal (code
, mips_zero
, 1); /* bal */
4074 mips_addu (code
, mips_t9
, mips_ra
, mips_at
);
4075 /* Table is 16 or 20 bytes from target of bal above */
4076 if (1 || !(cfg
->flags
& MONO_CFG_HAS_CALLS
)) {
4077 MIPS_MOVE (code
, mips_ra
, mips_t8
);
4078 mips_lw (code
, mips_t9
, mips_t9
, 20);
4081 mips_lw (code
, mips_t9
, mips_t9
, 16);
4082 mips_jalr (code
, mips_t9
, mips_t8
);
4084 for (i
= 0; i
< GPOINTER_TO_INT (ins
->klass
); ++i
)
4085 mips_emit32 (code
, 0xfefefefe);
4090 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4091 mips_beq (code
, mips_at
, mips_zero
, 2);
4093 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4099 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4100 mips_bltz (code
, mips_at
, 2);
4102 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4108 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4109 mips_bgtz (code
, mips_at
, 2);
4111 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4114 case OP_MIPS_COND_EXC_EQ
:
4115 case OP_MIPS_COND_EXC_GE
:
4116 case OP_MIPS_COND_EXC_GT
:
4117 case OP_MIPS_COND_EXC_LE
:
4118 case OP_MIPS_COND_EXC_LT
:
4119 case OP_MIPS_COND_EXC_NE_UN
:
4120 case OP_MIPS_COND_EXC_GE_UN
:
4121 case OP_MIPS_COND_EXC_GT_UN
:
4122 case OP_MIPS_COND_EXC_LE_UN
:
4123 case OP_MIPS_COND_EXC_LT_UN
:
4125 case OP_MIPS_COND_EXC_OV
:
4126 case OP_MIPS_COND_EXC_NO
:
4127 case OP_MIPS_COND_EXC_C
:
4128 case OP_MIPS_COND_EXC_NC
:
4130 case OP_MIPS_COND_EXC_IEQ
:
4131 case OP_MIPS_COND_EXC_IGE
:
4132 case OP_MIPS_COND_EXC_IGT
:
4133 case OP_MIPS_COND_EXC_ILE
:
4134 case OP_MIPS_COND_EXC_ILT
:
4135 case OP_MIPS_COND_EXC_INE_UN
:
4136 case OP_MIPS_COND_EXC_IGE_UN
:
4137 case OP_MIPS_COND_EXC_IGT_UN
:
4138 case OP_MIPS_COND_EXC_ILE_UN
:
4139 case OP_MIPS_COND_EXC_ILT_UN
:
4141 case OP_MIPS_COND_EXC_IOV
:
4142 case OP_MIPS_COND_EXC_INO
:
4143 case OP_MIPS_COND_EXC_IC
:
4144 case OP_MIPS_COND_EXC_INC
: {
4148 /* If the condition is true, raise the exception */
4150 /* need to reverse test to skip around exception raising */
4152 /* For the moment, branch around a branch to avoid reversing
4155 /* Remember, an unpatched branch to 0 branches to the delay slot */
4156 switch (ins
->opcode
) {
4157 case OP_MIPS_COND_EXC_EQ
:
4158 throw = (guint32
*)(void *)code
;
4159 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, 0);
4163 case OP_MIPS_COND_EXC_NE_UN
:
4164 throw = (guint32
*)(void *)code
;
4165 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, 0);
4169 case OP_MIPS_COND_EXC_LE_UN
:
4170 mips_sltu (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
4171 throw = (guint32
*)(void *)code
;
4172 mips_beq (code
, mips_at
, mips_zero
, 0);
4176 case OP_MIPS_COND_EXC_GT
:
4177 mips_slt (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
4178 throw = (guint32
*)(void *)code
;
4179 mips_bne (code
, mips_at
, mips_zero
, 0);
4183 case OP_MIPS_COND_EXC_GT_UN
:
4184 mips_sltu (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
4185 throw = (guint32
*)(void *)code
;
4186 mips_bne (code
, mips_at
, mips_zero
, 0);
4190 case OP_MIPS_COND_EXC_LT
:
4191 mips_slt (code
, mips_at
, ins
->sreg1
, ins
->sreg2
);
4192 throw = (guint32
*)(void *)code
;
4193 mips_bne (code
, mips_at
, mips_zero
, 0);
4197 case OP_MIPS_COND_EXC_LT_UN
:
4198 mips_sltu (code
, mips_at
, ins
->sreg1
, ins
->sreg2
);
4199 throw = (guint32
*)(void *)code
;
4200 mips_bne (code
, mips_at
, mips_zero
, 0);
4205 /* Not yet implemented */
4206 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins
->opcode
));
4207 g_assert_not_reached ();
4209 skip
= (guint32
*)(void *)code
;
4210 mips_beq (code
, mips_zero
, mips_zero
, 0);
4212 mips_patch (throw, (guint32
)code
);
4213 code
= mips_emit_exc_by_name (code
, ins
->inst_p1
);
4214 mips_patch (skip
, (guint32
)code
);
4215 cfg
->bb_exit
->max_offset
+= 24;
4224 code
= mips_emit_cond_branch (cfg
, code
, ins
->opcode
, ins
);
4227 /* floating point opcodes */
4230 if (((guint32
)ins
->inst_p0
) & (1 << 15))
4231 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16)+1);
4233 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16));
4234 mips_ldc1 (code
, ins
->dreg
, mips_at
, ((guint32
)ins
->inst_p0
) & 0xffff);
4236 mips_load_const (code
, mips_at
, ins
->inst_p0
);
4237 mips_lwc1 (code
, ins
->dreg
, mips_at
, ls_word_offset
);
4238 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, ms_word_offset
);
4242 if (((guint32
)ins
->inst_p0
) & (1 << 15))
4243 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16)+1);
4245 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16));
4246 mips_lwc1 (code
, ins
->dreg
, mips_at
, ((guint32
)ins
->inst_p0
) & 0xffff);
4247 #if PROMOTE_R4_TO_R8
4248 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4251 case OP_STORER8_MEMBASE_REG
:
4252 if (mips_is_imm16 (ins
->inst_offset
)) {
4253 #if _MIPS_SIM == _ABIO32
4254 mips_swc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
+ ls_word_offset
);
4255 mips_swc1 (code
, ins
->sreg1
+1, ins
->inst_destbasereg
, ins
->inst_offset
+ ms_word_offset
);
4256 #elif _MIPS_SIM == _ABIN32
4257 mips_sdc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
4260 mips_load_const (code
, mips_at
, ins
->inst_offset
);
4261 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
4262 mips_swc1 (code
, ins
->sreg1
, mips_at
, ls_word_offset
);
4263 mips_swc1 (code
, ins
->sreg1
+1, mips_at
, ms_word_offset
);
4266 case OP_LOADR8_MEMBASE
:
4267 if (mips_is_imm16 (ins
->inst_offset
)) {
4268 #if _MIPS_SIM == _ABIO32
4269 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
+ ls_word_offset
);
4270 mips_lwc1 (code
, ins
->dreg
+1, ins
->inst_basereg
, ins
->inst_offset
+ ms_word_offset
);
4271 #elif _MIPS_SIM == _ABIN32
4272 mips_ldc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4275 mips_load_const (code
, mips_at
, ins
->inst_offset
);
4276 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
4277 mips_lwc1 (code
, ins
->dreg
, mips_at
, ls_word_offset
);
4278 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, ms_word_offset
);
4281 case OP_STORER4_MEMBASE_REG
:
4282 g_assert (mips_is_imm16 (ins
->inst_offset
));
4283 #if PROMOTE_R4_TO_R8
4284 /* Need to convert ins->sreg1 to single-precision first */
4285 mips_cvtsd (code
, mips_ftemp
, ins
->sreg1
);
4286 mips_swc1 (code
, mips_ftemp
, ins
->inst_destbasereg
, ins
->inst_offset
);
4288 mips_swc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
4292 g_assert (mips_is_imm16 (ins
->inst_offset
));
4293 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4295 case OP_LOADR4_MEMBASE
:
4296 g_assert (mips_is_imm16 (ins
->inst_offset
));
4297 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4298 #if PROMOTE_R4_TO_R8
4299 /* Convert to double precision in place */
4300 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4303 case OP_LOADR4_MEMINDEX
:
4304 mips_addu (code
, mips_at
, ins
->inst_basereg
, ins
->sreg2
);
4305 mips_lwc1 (code
, ins
->dreg
, mips_at
, 0);
4307 case OP_LOADR8_MEMINDEX
:
4308 mips_addu (code
, mips_at
, ins
->inst_basereg
, ins
->sreg2
);
4309 #if _MIPS_SIM == _ABIO32
4310 mips_lwc1 (code
, ins
->dreg
, mips_at
, ls_word_offset
);
4311 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, ms_word_offset
);
4312 #elif _MIPS_SIM == _ABIN32
4313 mips_ldc1 (code
, ins
->dreg
, mips_at
, 0);
4316 case OP_STORER4_MEMINDEX
:
4317 mips_addu (code
, mips_at
, ins
->inst_destbasereg
, ins
->sreg2
);
4318 #if PROMOTE_R4_TO_R8
4319 /* Need to convert ins->sreg1 to single-precision first */
4320 mips_cvtsd (code
, mips_ftemp
, ins
->sreg1
);
4321 mips_swc1 (code
, mips_ftemp
, mips_at
, 0);
4323 mips_swc1 (code
, ins
->sreg1
, mips_at
, 0);
4326 case OP_STORER8_MEMINDEX
:
4327 mips_addu (code
, mips_at
, ins
->inst_destbasereg
, ins
->sreg2
);
4328 #if _MIPS_SIM == _ABIO32
4329 mips_swc1 (code
, ins
->sreg1
, mips_at
, ls_word_offset
);
4330 mips_swc1 (code
, ins
->sreg1
+1, mips_at
, ms_word_offset
);
4331 #elif _MIPS_SIM == _ABIN32
4332 mips_sdc1 (code
, ins
->sreg1
, mips_at
, 0);
4335 case OP_ICONV_TO_R_UN
: {
4336 static const guint64 adjust_val
= 0x41F0000000000000ULL
;
4338 /* convert unsigned int to double */
4339 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4340 mips_bgez (code
, ins
->sreg1
, 5);
4341 mips_cvtdw (code
, ins
->dreg
, mips_ftemp
);
4343 mips_load (code
, mips_at
, (guint32
) &adjust_val
);
4344 mips_ldc1 (code
, mips_ftemp
, mips_at
, 0);
4345 mips_faddd (code
, ins
->dreg
, ins
->dreg
, mips_ftemp
);
4346 /* target is here */
4349 case OP_ICONV_TO_R4
:
4350 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4351 mips_cvtsw (code
, ins
->dreg
, mips_ftemp
);
4352 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4354 case OP_ICONV_TO_R8
:
4355 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4356 mips_cvtdw (code
, ins
->dreg
, mips_ftemp
);
4358 case OP_FCONV_TO_I1
:
4359 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, TRUE
);
4361 case OP_FCONV_TO_U1
:
4362 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, FALSE
);
4364 case OP_FCONV_TO_I2
:
4365 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, TRUE
);
4367 case OP_FCONV_TO_U2
:
4368 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, FALSE
);
4370 case OP_FCONV_TO_I4
:
4372 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, TRUE
);
4374 case OP_FCONV_TO_U4
:
4376 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, FALSE
);
4379 mips_fsqrtd (code
, ins
->dreg
, ins
->sreg1
);
4382 mips_faddd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4385 mips_fsubd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4388 mips_fmuld (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4391 mips_fdivd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4394 mips_fnegd (code
, ins
->dreg
, ins
->sreg1
);
4397 mips_fcmpd (code
, MIPS_FPU_EQ
, ins
->sreg1
, ins
->sreg2
);
4398 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4399 mips_fbtrue (code
, 2);
4401 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4404 mips_fcmpd (code
, MIPS_FPU_LT
, ins
->sreg1
, ins
->sreg2
);
4405 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4406 mips_fbtrue (code
, 2);
4408 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4411 /* Less than, or Unordered */
4412 mips_fcmpd (code
, MIPS_FPU_ULT
, ins
->sreg1
, ins
->sreg2
);
4413 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4414 mips_fbtrue (code
, 2);
4416 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4419 mips_fcmpd (code
, MIPS_FPU_ULE
, ins
->sreg1
, ins
->sreg2
);
4420 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4421 mips_fbtrue (code
, 2);
4423 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4426 /* Greater than, or Unordered */
4427 mips_fcmpd (code
, MIPS_FPU_OLE
, ins
->sreg1
, ins
->sreg2
);
4428 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4429 mips_fbtrue (code
, 2);
4431 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4436 case OP_MIPS_FBLT_UN
:
4438 case OP_MIPS_FBGT_UN
:
4440 case OP_MIPS_FBGE_UN
:
4442 case OP_MIPS_FBLE_UN
: {
4444 gboolean is_true
= TRUE
, is_ordered
= FALSE
;
4445 guint32
*buf
= NULL
;
4447 switch (ins
->opcode
) {
4461 case OP_MIPS_FBLT_UN
:
4462 cond
= MIPS_FPU_ULT
;
4470 case OP_MIPS_FBGT_UN
:
4471 cond
= MIPS_FPU_OLE
;
4479 case OP_MIPS_FBGE_UN
:
4480 cond
= MIPS_FPU_OLT
;
4484 cond
= MIPS_FPU_OLE
;
4488 case OP_MIPS_FBLE_UN
:
4489 cond
= MIPS_FPU_ULE
;
4493 g_assert_not_reached ();
4497 /* Skip the check if unordered */
4498 mips_fcmpd (code
, MIPS_FPU_UN
, ins
->sreg1
, ins
->sreg2
);
4500 buf
= (guint32
*)code
;
4501 mips_fbtrue (code
, 0);
4505 mips_fcmpd (code
, cond
, ins
->sreg1
, ins
->sreg2
);
4507 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4509 mips_fbtrue (code
, 0);
4511 mips_fbfalse (code
, 0);
4515 mips_patch (buf
, (guint32
)code
);
4519 guint32
*branch_patch
;
4521 mips_mfc1 (code
, mips_at
, ins
->sreg1
+1);
4522 mips_srl (code
, mips_at
, mips_at
, 16+4);
4523 mips_andi (code
, mips_at
, mips_at
, 2047);
4524 mips_addiu (code
, mips_at
, mips_at
, -2047);
4526 branch_patch
= (guint32
*)(void *)code
;
4527 mips_bne (code
, mips_at
, mips_zero
, 0);
4530 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4531 mips_patch (branch_patch
, (guint32
)code
);
4532 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
4536 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_c1
, ins
->inst_p0
);
4537 mips_load (code
, ins
->dreg
, 0x0f0f0f0f);
4539 case OP_GC_SAFE_POINT
:
4544 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins
->opcode
), __FUNCTION__
);
4545 g_assert_not_reached ();
4548 if ((cfg
->opt
& MONO_OPT_BRANCH
) && ((code
- cfg
->native_code
- offset
) > max_len
)) {
4549 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4550 mono_inst_name (ins
->opcode
), max_len
, code
- cfg
->native_code
- offset
);
4551 g_assert_not_reached ();
4557 last_offset
= offset
;
4560 cfg
->code_len
= code
- cfg
->native_code
;
4564 mono_arch_register_lowlevel_calls (void)
4569 mono_arch_patch_code (MonoCompile
*cfg
, MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*ji
, gboolean run_cctors
, MonoError
*error
)
4571 MonoJumpInfo
*patch_info
;
4573 mono_error_init (error
);
4575 for (patch_info
= ji
; patch_info
; patch_info
= patch_info
->next
) {
4576 unsigned char *ip
= patch_info
->ip
.i
+ code
;
4577 const unsigned char *target
= NULL
;
4579 switch (patch_info
->type
) {
4580 case MONO_PATCH_INFO_IP
:
4581 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)ip
);
4583 case MONO_PATCH_INFO_SWITCH
: {
4584 gpointer
*table
= (gpointer
*)patch_info
->data
.table
->table
;
4587 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)table
);
4589 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
4590 table
[i
] = (int)patch_info
->data
.table
->table
[i
] + code
;
4594 case MONO_PATCH_INFO_METHODCONST
:
4595 case MONO_PATCH_INFO_CLASS
:
4596 case MONO_PATCH_INFO_IMAGE
:
4597 case MONO_PATCH_INFO_FIELD
:
4598 case MONO_PATCH_INFO_VTABLE
:
4599 case MONO_PATCH_INFO_IID
:
4600 case MONO_PATCH_INFO_SFLDA
:
4601 case MONO_PATCH_INFO_LDSTR
:
4602 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
4603 case MONO_PATCH_INFO_LDTOKEN
:
4604 case MONO_PATCH_INFO_R4
:
4605 case MONO_PATCH_INFO_R8
:
4606 /* from OP_AOTCONST : lui + addiu */
4607 target
= mono_resolve_patch_target (method
, domain
, code
, patch_info
, run_cctors
, error
);
4608 return_if_nok (error
);
4610 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)target
);
4613 case MONO_PATCH_INFO_EXC_NAME
:
4614 g_assert_not_reached ();
4615 *((gconstpointer
*)(void *)(ip
+ 1)) = patch_info
->data
.name
;
4618 case MONO_PATCH_INFO_NONE
:
4619 /* everything is dealt with at epilog output time */
4622 target
= mono_resolve_patch_target (method
, domain
, code
, patch_info
, run_cctors
, error
);
4623 return_if_nok (error
);
4625 mips_patch ((guint32
*)(void *)ip
, (guint32
)target
);
4632 * Allow tracing to work with this interface (with an optional argument)
4634 * This code is expected to be inserted just after the 'real' prolog code,
4635 * and before the first basic block. We need to allocate a 2nd, temporary
4636 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4640 mono_arch_instrument_prolog (MonoCompile
*cfg
, void *func
, void *p
, gboolean enable_arguments
)
4643 int offset
= cfg
->arch
.tracing_offset
;
4649 MIPS_SW (code
, mips_a0
, mips_sp
, offset
+ 0*SIZEOF_REGISTER
);
4650 MIPS_SW (code
, mips_a1
, mips_sp
, offset
+ 1*SIZEOF_REGISTER
);
4651 MIPS_SW (code
, mips_a2
, mips_sp
, offset
+ 2*SIZEOF_REGISTER
);
4652 MIPS_SW (code
, mips_a3
, mips_sp
, offset
+ 3*SIZEOF_REGISTER
);
4653 #if _MIPS_SIM == _ABIN32
4655 /* FIXME: Need a separate region for these */
4656 MIPS_SW (code
, mips_a4
, mips_sp
, offset
+ 4*SIZEOF_REGISTER
);
4657 MIPS_SW (code
, mips_a5
, mips_sp
, offset
+ 5*SIZEOF_REGISTER
);
4658 MIPS_SW (code
, mips_a6
, mips_sp
, offset
+ 6*SIZEOF_REGISTER
);
4659 MIPS_SW (code
, mips_a7
, mips_sp
, offset
+ 7*SIZEOF_REGISTER
);
4663 mips_load_const (code
, mips_a0
, cfg
->method
);
4664 mips_addiu (code
, mips_a1
, mips_sp
, offset
);
4665 mips_call (code
, mips_t9
, func
);
4668 MIPS_LW (code
, mips_a0
, mips_sp
, offset
+ 0*SIZEOF_REGISTER
);
4669 MIPS_LW (code
, mips_a1
, mips_sp
, offset
+ 1*SIZEOF_REGISTER
);
4670 MIPS_LW (code
, mips_a2
, mips_sp
, offset
+ 2*SIZEOF_REGISTER
);
4671 MIPS_LW (code
, mips_a3
, mips_sp
, offset
+ 3*SIZEOF_REGISTER
);
4672 #if _MIPS_SIM == _ABIN32
4675 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4676 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4677 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4678 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4689 mips_adjust_stackframe(MonoCompile
*cfg
)
4692 int delta
, threshold
, i
;
4693 MonoMethodSignature
*sig
;
4696 if (cfg
->stack_offset
== cfg
->arch
.local_alloc_offset
)
4699 /* adjust cfg->stack_offset for account for down-spilling */
4700 cfg
->stack_offset
+= SIZEOF_REGISTER
;
4702 /* re-align cfg->stack_offset if needed (due to var spilling) */
4703 cfg
->stack_offset
= (cfg
->stack_offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
4704 delta
= cfg
->stack_offset
- cfg
->arch
.local_alloc_offset
;
4705 if (cfg
->verbose_level
> 2) {
4706 g_print ("mips_adjust_stackframe:\n");
4707 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg
->arch
.local_alloc_offset
, cfg
->stack_offset
);
4709 threshold
= cfg
->arch
.local_alloc_offset
;
4710 ra_offset
= cfg
->stack_offset
- sizeof(gpointer
);
4711 if (cfg
->verbose_level
> 2) {
4712 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset
, ra_offset
, delta
, delta
);
4715 sig
= mono_method_signature (cfg
->method
);
4716 if (sig
&& sig
->ret
&& MONO_TYPE_ISSTRUCT (sig
->ret
)) {
4717 cfg
->vret_addr
->inst_offset
+= delta
;
4719 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4720 MonoInst
*inst
= cfg
->args
[i
];
4722 inst
->inst_offset
+= delta
;
4726 * loads and stores based off the frame reg that (used to) lie
4727 * above the spill var area need to be increased by 'delta'
4728 * to make room for the spill vars.
4730 /* Need to find loads and stores to adjust that
4731 * are above where the spillvars were inserted, but
4732 * which are not the spillvar references themselves.
4734 * Idea - since all offsets from fp are positive, make
4735 * spillvar offsets negative to begin with so we can spot
4740 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
4744 if (cfg
->verbose_level
> 2) {
4745 g_print ("BASIC BLOCK %d:\n", bb
->block_num
);
4747 MONO_BB_FOR_EACH_INS (bb
, ins
) {
4751 if (cfg
->verbose_level
> 2) {
4752 mono_print_ins_index (ins_cnt
, ins
);
4754 /* The == mips_sp tests catch FP spills */
4755 if (MONO_IS_LOAD_MEMBASE(ins
) && ((ins
->inst_basereg
== mips_fp
) ||
4756 (ins
->inst_basereg
== mips_sp
))) {
4757 switch (ins
->opcode
) {
4758 case OP_LOADI8_MEMBASE
:
4759 case OP_LOADR8_MEMBASE
:
4766 } else if (MONO_IS_STORE_MEMBASE(ins
) && ((ins
->dreg
== mips_fp
) ||
4767 (ins
->dreg
== mips_sp
))) {
4768 switch (ins
->opcode
) {
4769 case OP_STOREI8_MEMBASE_REG
:
4770 case OP_STORER8_MEMBASE_REG
:
4771 case OP_STOREI8_MEMBASE_IMM
:
4779 if (((ins
->opcode
== OP_ADD_IMM
) || (ins
->opcode
== OP_IADD_IMM
)) && (ins
->sreg1
== cfg
->frame_reg
))
4782 if (ins
->inst_c0
>= threshold
) {
4783 ins
->inst_c0
+= delta
;
4784 if (cfg
->verbose_level
> 2) {
4786 mono_print_ins_index (ins_cnt
, ins
);
4789 else if (ins
->inst_c0
< 0) {
4790 /* Adj_c0 holds the size of the datatype. */
4791 ins
->inst_c0
= - ins
->inst_c0
- adj_c0
;
4792 if (cfg
->verbose_level
> 2) {
4794 mono_print_ins_index (ins_cnt
, ins
);
4797 g_assert (ins
->inst_c0
!= ra_offset
);
4800 if (ins
->inst_imm
>= threshold
) {
4801 ins
->inst_imm
+= delta
;
4802 if (cfg
->verbose_level
> 2) {
4804 mono_print_ins_index (ins_cnt
, ins
);
4807 g_assert (ins
->inst_c0
!= ra_offset
);
4817 * Stack frame layout:
4819 * ------------------- sp + cfg->stack_usage + cfg->param_area
4820 * param area incoming
4821 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4823 * ------------------- sp + cfg->stack_usage
4825 * ------------------- sp + cfg->stack_usage-4
4827 * ------------------- sp +
4828 * MonoLMF structure optional
4829 * ------------------- sp + cfg->arch.lmf_offset
4830 * saved registers s0-s8
4831 * ------------------- sp + cfg->arch.iregs_offset
4833 * ------------------- sp + cfg->param_area
4834 * param area outgoing
4835 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4837 * ------------------- sp
4841 mono_arch_emit_prolog (MonoCompile
*cfg
)
4843 MonoMethod
*method
= cfg
->method
;
4844 MonoMethodSignature
*sig
;
4846 int alloc_size
, pos
, i
, max_offset
;
4847 int alloc2_size
= 0;
4851 guint32 iregs_to_save
= 0;
4853 guint32 fregs_to_save
= 0;
4855 /* lmf_offset is the offset of the LMF from our stack pointer. */
4856 guint32 lmf_offset
= cfg
->arch
.lmf_offset
;
4860 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
))
4864 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
4866 sig
= mono_method_signature (method
);
4867 cfg
->code_size
= 768 + sig
->param_count
* 20;
4868 code
= cfg
->native_code
= g_malloc (cfg
->code_size
);
4871 * compute max_offset in order to use short forward jumps.
4874 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
4875 MonoInst
*ins
= bb
->code
;
4876 bb
->max_offset
= max_offset
;
4878 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
)
4881 MONO_BB_FOR_EACH_INS (bb
, ins
)
4882 max_offset
+= ((guint8
*)ins_get_spec (ins
->opcode
))[MONO_INST_LEN
];
4884 if (max_offset
> 0xffff)
4885 cfg
->arch
.long_branch
= TRUE
;
4888 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4889 * This means that we have to adjust the offsets inside instructions which reference
4890 * arguments received on the stack, since the initial offset doesn't take into
4891 * account spill slots.
4893 mips_adjust_stackframe (cfg
);
4895 /* Offset between current sp and the CFA */
4897 mono_emit_unwind_op_def_cfa (cfg
, code
, mips_sp
, cfa_offset
);
4899 /* stack_offset should not be changed here. */
4900 alloc_size
= cfg
->stack_offset
;
4901 cfg
->stack_usage
= alloc_size
;
4903 iregs_to_save
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
4906 fregs_to_save
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
4908 fregs_to_save
= MONO_ARCH_CALLEE_SAVED_FREGS
;
4909 fregs_to_save
|= (fregs_to_save
<< 1);
4912 /* If the stack size is too big, save 1024 bytes to start with
4913 * so the prologue can use imm16(reg) addressing, then allocate
4914 * the rest of the frame.
4916 if (alloc_size
> ((1 << 15) - 1024)) {
4917 alloc2_size
= alloc_size
- 1024;
4921 g_assert (mips_is_imm16 (-alloc_size
));
4922 mips_addiu (code
, mips_sp
, mips_sp
, -alloc_size
);
4923 cfa_offset
= alloc_size
;
4924 mono_emit_unwind_op_def_cfa_offset (cfg
, code
, cfa_offset
);
4927 if ((cfg
->flags
& MONO_CFG_HAS_CALLS
) || ALWAYS_SAVE_RA
) {
4928 int offset
= alloc_size
+ MIPS_RET_ADDR_OFFSET
;
4929 if (mips_is_imm16(offset
))
4930 mips_sw (code
, mips_ra
, mips_sp
, offset
);
4932 g_assert_not_reached ();
4934 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4935 mono_emit_unwind_op_offset (cfg
, code
, mips_ra
, offset
- cfa_offset
);
4938 /* XXX - optimize this later to not save all regs if LMF constructed */
4939 pos
= cfg
->arch
.iregs_offset
- alloc2_size
;
4941 if (iregs_to_save
) {
4942 /* save used registers in own stack frame (at pos) */
4943 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
4944 if (iregs_to_save
& (1 << i
)) {
4945 g_assert (pos
< (int)(cfg
->stack_usage
- sizeof(gpointer
)));
4946 g_assert (mips_is_imm16(pos
));
4947 MIPS_SW (code
, i
, mips_sp
, pos
);
4948 mono_emit_unwind_op_offset (cfg
, code
, i
, pos
- cfa_offset
);
4949 pos
+= SIZEOF_REGISTER
;
4954 // FIXME: Don't save registers twice if there is an LMF
4955 // s8 has to be special cased since it is overwritten with the updated value
4957 if (method
->save_lmf
) {
4958 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
4959 int offset
= lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, iregs
[i
]);
4960 g_assert (mips_is_imm16(offset
));
4961 if (MIPS_LMF_IREGMASK
& (1 << i
))
4962 MIPS_SW (code
, i
, mips_sp
, offset
);
4967 /* Save float registers */
4968 if (fregs_to_save
) {
4969 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
4970 if (fregs_to_save
& (1 << i
)) {
4971 g_assert (pos
< cfg
->stack_usage
- MIPS_STACK_ALIGNMENT
);
4972 g_assert (mips_is_imm16(pos
));
4973 mips_swc1 (code
, i
, mips_sp
, pos
);
4974 pos
+= sizeof (gulong
);
4979 if (method
->save_lmf
) {
4980 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
4981 int offset
= lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, fregs
[i
]);
4982 g_assert (mips_is_imm16(offset
));
4983 mips_swc1 (code
, i
, mips_sp
, offset
);
4988 if (cfg
->frame_reg
!= mips_sp
) {
4989 MIPS_MOVE (code
, cfg
->frame_reg
, mips_sp
);
4990 mono_emit_unwind_op_def_cfa (cfg
, code
, cfg
->frame_reg
, cfa_offset
);
4992 if (method
->save_lmf
) {
4993 int offset
= lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, iregs
[cfg
->frame_reg
]);
4994 g_assert (mips_is_imm16(offset
));
4995 MIPS_SW (code
, cfg
->frame_reg
, mips_sp
, offset
);
4999 /* store runtime generic context */
5000 if (cfg
->rgctx_var
) {
5001 MonoInst
*ins
= cfg
->rgctx_var
;
5003 g_assert (ins
->opcode
== OP_REGOFFSET
);
5005 g_assert (mips_is_imm16 (ins
->inst_offset
));
5006 mips_sw (code
, MONO_ARCH_RGCTX_REG
, ins
->inst_basereg
, ins
->inst_offset
);
5009 /* load arguments allocated to register from the stack */
5012 if (!cfg
->arch
.cinfo
)
5013 cfg
->arch
.cinfo
= get_call_info (cfg
->mempool
, sig
);
5014 cinfo
= cfg
->arch
.cinfo
;
5016 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
5017 ArgInfo
*ainfo
= &cinfo
->ret
;
5018 inst
= cfg
->vret_addr
;
5019 if (inst
->opcode
== OP_REGVAR
)
5020 MIPS_MOVE (code
, inst
->dreg
, ainfo
->reg
);
5021 else if (mips_is_imm16 (inst
->inst_offset
)) {
5022 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
5024 mips_load_const (code
, mips_at
, inst
->inst_offset
);
5025 mips_addu (code
, mips_at
, mips_at
, inst
->inst_basereg
);
5026 mips_sw (code
, ainfo
->reg
, mips_at
, 0);
5030 if (sig
->call_convention
== MONO_CALL_VARARG
) {
5031 ArgInfo
*cookie
= &cinfo
->sig_cookie
;
5032 int offset
= alloc_size
+ cookie
->offset
;
5034 /* Save the sig cookie address */
5035 g_assert (cookie
->storage
== ArgOnStack
);
5037 g_assert (mips_is_imm16(offset
));
5038 mips_addi (code
, mips_at
, cfg
->frame_reg
, offset
);
5039 mips_sw (code
, mips_at
, cfg
->frame_reg
, cfg
->sig_cookie
- alloc2_size
);
5042 /* Keep this in sync with emit_load_volatile_arguments */
5043 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
5044 ArgInfo
*ainfo
= cinfo
->args
+ i
;
5045 inst
= cfg
->args
[pos
];
5047 if (cfg
->verbose_level
> 2)
5048 g_print ("Saving argument %d (type: %d)\n", i
, ainfo
->storage
);
5049 if (inst
->opcode
== OP_REGVAR
) {
5050 /* Argument ends up in a register */
5051 if (ainfo
->storage
== ArgInIReg
)
5052 MIPS_MOVE (code
, inst
->dreg
, ainfo
->reg
);
5053 else if (ainfo
->storage
== ArgInFReg
) {
5054 g_assert_not_reached();
5056 ppc_fmr (code
, inst
->dreg
, ainfo
->reg
);
5059 else if (ainfo
->storage
== ArgOnStack
) {
5060 int offset
= cfg
->stack_usage
+ ainfo
->offset
;
5061 g_assert (mips_is_imm16(offset
));
5062 mips_lw (code
, inst
->dreg
, mips_sp
, offset
);
5064 g_assert_not_reached ();
5066 if (cfg
->verbose_level
> 2)
5067 g_print ("Argument %d assigned to register %s\n", pos
, mono_arch_regname (inst
->dreg
));
5069 /* Argument ends up on the stack */
5070 if (ainfo
->storage
== ArgInIReg
) {
5072 /* Incoming parameters should be above this frame */
5073 if (cfg
->verbose_level
> 2)
5074 g_print ("stack slot at %d of %d+%d\n",
5075 inst
->inst_offset
, alloc_size
, alloc2_size
);
5076 /* g_assert (inst->inst_offset >= alloc_size); */
5077 g_assert (inst
->inst_basereg
== cfg
->frame_reg
);
5078 basereg_offset
= inst
->inst_offset
- alloc2_size
;
5079 g_assert (mips_is_imm16 (basereg_offset
));
5080 switch (ainfo
->size
) {
5082 mips_sb (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
);
5085 mips_sh (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
);
5089 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
);
5092 #if (SIZEOF_REGISTER == 4)
5093 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
+ ls_word_offset
);
5094 mips_sw (code
, ainfo
->reg
+ 1, inst
->inst_basereg
, basereg_offset
+ ms_word_offset
);
5095 #elif (SIZEOF_REGISTER == 8)
5096 mips_sd (code
, ainfo
->reg
, inst
->inst_basereg
, basereg_offset
);
5100 g_assert_not_reached ();
5103 } else if (ainfo
->storage
== ArgOnStack
) {
5105 * Argument comes in on the stack, and ends up on the stack
5106 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5107 * 8 and 16 bit quantities. Shorten them in place.
5109 g_assert (mips_is_imm16 (inst
->inst_offset
));
5110 switch (ainfo
->size
) {
5112 mips_lw (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
5113 mips_sb (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
5116 mips_lw (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
5117 mips_sh (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
5124 g_assert_not_reached ();
5126 } else if (ainfo
->storage
== ArgInFReg
) {
5127 g_assert (mips_is_imm16 (inst
->inst_offset
));
5128 g_assert (mips_is_imm16 (inst
->inst_offset
+4));
5129 if (ainfo
->size
== 8) {
5130 #if _MIPS_SIM == _ABIO32
5131 mips_swc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+ ls_word_offset
);
5132 mips_swc1 (code
, ainfo
->reg
+1, inst
->inst_basereg
, inst
->inst_offset
+ ms_word_offset
);
5133 #elif _MIPS_SIM == _ABIN32
5134 mips_sdc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
5137 else if (ainfo
->size
== 4)
5138 mips_swc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
5140 g_assert_not_reached ();
5141 } else if (ainfo
->storage
== ArgStructByVal
) {
5143 int doffset
= inst
->inst_offset
;
5145 g_assert (mips_is_imm16 (inst
->inst_offset
));
5146 g_assert (mips_is_imm16 (inst
->inst_offset
+ ainfo
->size
* sizeof (gpointer
)));
5147 /* Push the argument registers into their stack slots */
5148 for (i
= 0; i
< ainfo
->size
; ++i
) {
5149 g_assert (mips_is_imm16(doffset
));
5150 MIPS_SW (code
, ainfo
->reg
+ i
, inst
->inst_basereg
, doffset
);
5151 doffset
+= SIZEOF_REGISTER
;
5153 } else if (ainfo
->storage
== ArgStructByAddr
) {
5154 g_assert (mips_is_imm16 (inst
->inst_offset
));
5155 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5156 code
= emit_memcpy (code
, ainfo
->vtsize
* sizeof (gpointer
), inst
->inst_basereg
, inst
->inst_offset
, ainfo
->reg
, 0);
5158 g_assert_not_reached ();
5163 if (method
->save_lmf
) {
5164 mips_load_const (code
, mips_at
, MIPS_LMF_MAGIC1
);
5165 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, magic
));
5167 if (lmf_pthread_key
!= -1) {
5168 g_assert_not_reached();
5170 emit_tls_access (code
, mips_temp
, lmf_pthread_key
);
5172 if (G_STRUCT_OFFSET (MonoJitTlsData
, lmf
)) {
5173 int offset
= G_STRUCT_OFFSET (MonoJitTlsData
, lmf
);
5174 g_assert (mips_is_imm16(offset
));
5175 mips_addiu (code
, mips_a0
, mips_temp
, offset
);
5178 /* This can/will clobber the a0-a3 registers */
5179 mips_call (code
, mips_t9
, (gpointer
)mono_get_lmf_addr
);
5182 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5183 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
)));
5184 mips_sw (code
, mips_v0
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
5185 /* new_lmf->previous_lmf = *lmf_addr */
5186 mips_lw (code
, mips_at
, mips_v0
, 0);
5187 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
)));
5188 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
5189 /* *(lmf_addr) = sp + lmf_offset */
5190 g_assert (mips_is_imm16(lmf_offset
));
5191 mips_addiu (code
, mips_at
, mips_sp
, lmf_offset
);
5192 mips_sw (code
, mips_at
, mips_v0
, 0);
5194 /* save method info */
5195 mips_load_const (code
, mips_at
, method
);
5196 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, method
)));
5197 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, method
));
5199 /* save the current IP */
5200 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_IP
, NULL
);
5201 mips_load_const (code
, mips_at
, 0x01010101);
5202 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, eip
));
5206 if (mips_is_imm16 (-alloc2_size
)) {
5207 mips_addu (code
, mips_sp
, mips_sp
, -alloc2_size
);
5210 mips_load_const (code
, mips_at
, -alloc2_size
);
5211 mips_addu (code
, mips_sp
, mips_sp
, mips_at
);
5213 alloc_size
+= alloc2_size
;
5214 cfa_offset
+= alloc2_size
;
5215 if (cfg
->frame_reg
!= mips_sp
)
5216 MIPS_MOVE (code
, cfg
->frame_reg
, mips_sp
);
5218 mono_emit_unwind_op_def_cfa_offset (cfg
, code
, cfa_offset
);
5222 #if _MIPS_SIM == _ABIO32
5223 cfg
->arch
.tracing_offset
= cfg
->stack_offset
;
5224 #elif _MIPS_SIM == _ABIN32
5225 /* no stack slots by default for argument regs, reserve a special block */
5226 g_assert_not_reached ();
5228 code
= mono_arch_instrument_prolog (cfg
, mono_trace_enter_method
, code
, TRUE
);
5231 cfg
->code_len
= code
- cfg
->native_code
;
5232 g_assert (cfg
->code_len
< cfg
->code_size
);
5246 mono_arch_instrument_epilog_full (MonoCompile
*cfg
, void *func
, void *p
, gboolean enable_arguments
, gboolean preserve_argument_registers
)
5249 int save_mode
= SAVE_NONE
;
5251 MonoMethod
*method
= cfg
->method
;
5252 int rtype
= mini_get_underlying_type (mono_method_signature (method
)->ret
)->type
;
5253 int save_offset
= MIPS_STACK_PARAM_OFFSET
;
5255 g_assert ((save_offset
& (MIPS_STACK_ALIGNMENT
-1)) == 0);
5257 offset
= code
- cfg
->native_code
;
5258 /* we need about 16 instructions */
5259 if (offset
> (cfg
->code_size
- 16 * 4)) {
5260 cfg
->code_size
*= 2;
5261 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
5262 code
= cfg
->native_code
+ offset
;
5267 case MONO_TYPE_VOID
:
5268 /* special case string .ctor icall */
5269 if (strcmp (".ctor", method
->name
) && method
->klass
== mono_defaults
.string_class
)
5270 save_mode
= SAVE_ONE
;
5272 save_mode
= SAVE_NONE
;
5276 save_mode
= SAVE_FP
;
5278 case MONO_TYPE_VALUETYPE
:
5279 save_mode
= SAVE_STRUCT
;
5283 #if SIZEOF_REGISTER == 4
5284 save_mode
= SAVE_TWO
;
5285 #elif SIZEOF_REGISTER == 8
5286 save_mode
= SAVE_ONE
;
5290 save_mode
= SAVE_ONE
;
5294 mips_addiu (code
, mips_sp
, mips_sp
, -32);
5295 g_assert (mips_is_imm16(save_offset
));
5296 switch (save_mode
) {
5298 mips_sw (code
, mips_v0
, mips_sp
, save_offset
);
5299 g_assert (mips_is_imm16(save_offset
+ SIZEOF_REGISTER
));
5300 mips_sw (code
, mips_v1
, mips_sp
, save_offset
+ SIZEOF_REGISTER
);
5301 if (enable_arguments
) {
5302 MIPS_MOVE (code
, mips_a1
, mips_v0
);
5303 MIPS_MOVE (code
, mips_a2
, mips_v1
);
5307 MIPS_SW (code
, mips_v0
, mips_sp
, save_offset
);
5308 if (enable_arguments
) {
5309 MIPS_MOVE (code
, mips_a1
, mips_v0
);
5313 mips_sdc1 (code
, mips_f0
, mips_sp
, save_offset
);
5314 mips_ldc1 (code
, mips_f12
, mips_sp
, save_offset
);
5315 mips_lw (code
, mips_a0
, mips_sp
, save_offset
);
5316 g_assert (mips_is_imm16(save_offset
+ SIZEOF_REGISTER
));
5317 mips_lw (code
, mips_a1
, mips_sp
, save_offset
+ SIZEOF_REGISTER
);
5324 mips_load_const (code
, mips_a0
, cfg
->method
);
5325 mips_call (code
, mips_t9
, func
);
5327 switch (save_mode
) {
5329 mips_lw (code
, mips_v0
, mips_sp
, save_offset
);
5330 g_assert (mips_is_imm16(save_offset
+ SIZEOF_REGISTER
));
5331 mips_lw (code
, mips_v1
, mips_sp
, save_offset
+ SIZEOF_REGISTER
);
5334 MIPS_LW (code
, mips_v0
, mips_sp
, save_offset
);
5337 mips_ldc1 (code
, mips_f0
, mips_sp
, save_offset
);
5344 mips_addiu (code
, mips_sp
, mips_sp
, 32);
5351 mono_arch_emit_epilog_sub (MonoCompile
*cfg
, guint8
*code
)
5353 MonoMethod
*method
= cfg
->method
;
5355 int max_epilog_size
= 16 + 20*4;
5356 int alloc2_size
= 0;
5357 guint32 iregs_to_restore
;
5359 guint32 fregs_to_restore
;
5362 if (cfg
->method
->save_lmf
)
5363 max_epilog_size
+= 128;
5365 if (mono_jit_trace_calls
!= NULL
)
5366 max_epilog_size
+= 50;
5368 if (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
)
5369 max_epilog_size
+= 50;
5372 pos
= code
- cfg
->native_code
;
5373 while (cfg
->code_len
+ max_epilog_size
> (cfg
->code_size
- 16)) {
5374 cfg
->code_size
*= 2;
5375 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
5376 cfg
->stat_code_reallocs
++;
5380 * Keep in sync with OP_JMP
5383 code
= cfg
->native_code
+ pos
;
5385 code
= cfg
->native_code
+ cfg
->code_len
;
5387 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
)) {
5388 code
= mono_arch_instrument_epilog (cfg
, mono_trace_leave_method
, code
, TRUE
);
5390 if (cfg
->frame_reg
!= mips_sp
) {
5391 MIPS_MOVE (code
, mips_sp
, cfg
->frame_reg
);
5393 /* If the stack frame is really large, deconstruct it in two steps */
5394 if (cfg
->stack_usage
> ((1 << 15) - 1024)) {
5395 alloc2_size
= cfg
->stack_usage
- 1024;
5396 /* partially deconstruct the stack */
5397 mips_load_const (code
, mips_at
, alloc2_size
);
5398 mips_addu (code
, mips_sp
, mips_sp
, mips_at
);
5400 pos
= cfg
->arch
.iregs_offset
- alloc2_size
;
5401 iregs_to_restore
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
5402 if (iregs_to_restore
) {
5403 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
5404 if (iregs_to_restore
& (1 << i
)) {
5405 g_assert (mips_is_imm16(pos
));
5406 MIPS_LW (code
, i
, mips_sp
, pos
);
5407 pos
+= SIZEOF_REGISTER
;
5414 fregs_to_restore
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
5416 fregs_to_restore
= MONO_ARCH_CALLEE_SAVED_FREGS
;
5417 fregs_to_restore
|= (fregs_to_restore
<< 1);
5419 if (fregs_to_restore
) {
5420 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
5421 if (fregs_to_restore
& (1 << i
)) {
5422 g_assert (pos
< cfg
->stack_usage
- MIPS_STACK_ALIGNMENT
);
5423 g_assert (mips_is_imm16(pos
));
5424 mips_lwc1 (code
, i
, mips_sp
, pos
);
5431 /* Unlink the LMF if necessary */
5432 if (method
->save_lmf
) {
5433 int lmf_offset
= cfg
->arch
.lmf_offset
;
5435 /* t0 = current_lmf->previous_lmf */
5436 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
)));
5437 mips_lw (code
, mips_temp
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
5439 g_assert (mips_is_imm16(lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
)));
5440 mips_lw (code
, mips_t1
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
5441 /* (*lmf_addr) = previous_lmf */
5442 mips_sw (code
, mips_temp
, mips_t1
, 0);
5446 /* Restore the fp */
5447 mips_lw (code
, mips_fp
, mips_sp
, cfg
->stack_usage
+ MIPS_FP_ADDR_OFFSET
);
5450 if ((cfg
->flags
& MONO_CFG_HAS_CALLS
) || ALWAYS_SAVE_RA
) {
5451 g_assert (mips_is_imm16(cfg
->stack_usage
- alloc2_size
+ MIPS_RET_ADDR_OFFSET
));
5452 mips_lw (code
, mips_ra
, mips_sp
, cfg
->stack_usage
- alloc2_size
+ MIPS_RET_ADDR_OFFSET
);
5454 /* Restore the stack pointer */
5455 g_assert (mips_is_imm16(cfg
->stack_usage
- alloc2_size
));
5456 mips_addiu (code
, mips_sp
, mips_sp
, cfg
->stack_usage
- alloc2_size
);
5458 /* Caller will emit either return or tail-call sequence */
5460 cfg
->code_len
= code
- cfg
->native_code
;
5462 g_assert (cfg
->code_len
< cfg
->code_size
);
5467 mono_arch_emit_epilog (MonoCompile
*cfg
)
5471 code
= mono_arch_emit_epilog_sub (cfg
, NULL
);
5473 mips_jr (code
, mips_ra
);
5476 cfg
->code_len
= code
- cfg
->native_code
;
5478 g_assert (cfg
->code_len
< cfg
->code_size
);
5481 /* remove once throw_exception_by_name is eliminated */
5484 exception_id_by_name (const char *name
)
5486 if (strcmp (name
, "IndexOutOfRangeException") == 0)
5487 return MONO_EXC_INDEX_OUT_OF_RANGE
;
5488 if (strcmp (name
, "OverflowException") == 0)
5489 return MONO_EXC_OVERFLOW
;
5490 if (strcmp (name
, "ArithmeticException") == 0)
5491 return MONO_EXC_ARITHMETIC
;
5492 if (strcmp (name
, "DivideByZeroException") == 0)
5493 return MONO_EXC_DIVIDE_BY_ZERO
;
5494 if (strcmp (name
, "InvalidCastException") == 0)
5495 return MONO_EXC_INVALID_CAST
;
5496 if (strcmp (name
, "NullReferenceException") == 0)
5497 return MONO_EXC_NULL_REF
;
5498 if (strcmp (name
, "ArrayTypeMismatchException") == 0)
5499 return MONO_EXC_ARRAY_TYPE_MISMATCH
;
5500 if (strcmp (name
, "ArgumentException") == 0)
5501 return MONO_EXC_ARGUMENT
;
5502 g_error ("Unknown intrinsic exception %s\n", name
);
5508 mono_arch_emit_exceptions (MonoCompile
*cfg
)
5511 MonoJumpInfo
*patch_info
;
5514 const guint8
* exc_throw_pos
[MONO_EXC_INTRINS_NUM
] = {NULL
};
5515 guint8 exc_throw_found
[MONO_EXC_INTRINS_NUM
] = {0};
5516 int max_epilog_size
= 50;
5518 /* count the number of exception infos */
5521 * make sure we have enough space for exceptions
5522 * 24 is the simulated call to throw_exception_by_name
5524 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5526 if (patch_info
->type
== MONO_PATCH_INFO_EXC
) {
5527 i
= exception_id_by_name (patch_info
->data
.target
);
5528 g_assert (i
< MONO_EXC_INTRINS_NUM
);
5529 if (!exc_throw_found
[i
]) {
5530 max_epilog_size
+= 12;
5531 exc_throw_found
[i
] = TRUE
;
5537 while (cfg
->code_len
+ max_epilog_size
> (cfg
->code_size
- 16)) {
5538 cfg
->code_size
*= 2;
5539 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
5540 cfg
->stat_code_reallocs
++;
5543 code
= cfg
->native_code
+ cfg
->code_len
;
5545 /* add code to raise exceptions */
5546 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5547 switch (patch_info
->type
) {
5548 case MONO_PATCH_INFO_EXC
: {
5550 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5552 i
= exception_id_by_name (patch_info
->data
.target
);
5553 g_assert (i
>= 0 && i
< MONO_EXC_INTRINS_NUM
);
5554 if (!exc_throw_pos
[i
]) {
5557 exc_throw_pos
[i
] = code
;
5558 //g_print ("exc: writing stub at %p\n", code);
5559 mips_load_const (code
, mips_a0
, patch_info
->data
.target
);
5560 addr
= (guint32
) mono_arch_get_throw_exception_by_name ();
5561 mips_load_const (code
, mips_t9
, addr
);
5562 mips_jr (code
, mips_t9
);
5565 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5567 /* Turn into a Relative patch, pointing at code stub */
5568 patch_info
->type
= MONO_PATCH_INFO_METHOD_REL
;
5569 patch_info
->data
.offset
= exc_throw_pos
[i
] - cfg
->native_code
;
5571 g_assert_not_reached();
5581 cfg
->code_len
= code
- cfg
->native_code
;
5583 g_assert (cfg
->code_len
< cfg
->code_size
);
5588 * Thread local storage support
5591 setup_tls_access (void)
5594 //guint32 *ins, *code;
5596 if (tls_mode
== TLS_MODE_FAILED
)
5599 if (g_getenv ("MONO_NO_TLS")) {
5600 tls_mode
= TLS_MODE_FAILED
;
5604 if (tls_mode
== TLS_MODE_DETECT
) {
5606 tls_mode
= TLS_MODE_FAILED
;
5610 ins
= (guint32
*)pthread_getspecific
;
5611 /* uncond branch to the real method */
5612 if ((*ins
>> 26) == 18) {
5614 val
= (*ins
& ~3) << 6;
5618 ins
= (guint32
*)val
;
5620 ins
= (guint32
*) ((char*)ins
+ val
);
5623 code
= &cmplwi_1023
;
5624 ppc_cmpli (code
, 0, 0, ppc_r3
, 1023);
5626 ppc_li (code
, ppc_r4
, 0x48);
5629 if (*ins
== cmplwi_1023
) {
5630 int found_lwz_284
= 0;
5631 for (ptk
= 0; ptk
< 20; ++ptk
) {
5633 if (!*ins
|| *ins
== blr_ins
)
5635 if ((guint16
)*ins
== 284 && (*ins
>> 26) == 32) {
5640 if (!found_lwz_284
) {
5641 tls_mode
= TLS_MODE_FAILED
;
5644 tls_mode
= TLS_MODE_LTHREADS
;
5645 } else if (*ins
== li_0x48
) {
5647 /* uncond branch to the real method */
5648 if ((*ins
>> 26) == 18) {
5650 val
= (*ins
& ~3) << 6;
5654 ins
= (guint32
*)val
;
5656 ins
= (guint32
*) ((char*)ins
+ val
);
5659 ppc_li (code
, ppc_r0
, 0x7FF2);
5660 if (ins
[1] == val
) {
5661 /* Darwin on G4, implement */
5662 tls_mode
= TLS_MODE_FAILED
;
5666 ppc_mfspr (code
, ppc_r3
, 104);
5667 if (ins
[1] != val
) {
5668 tls_mode
= TLS_MODE_FAILED
;
5671 tls_mode
= TLS_MODE_DARWIN_G5
;
5674 tls_mode
= TLS_MODE_FAILED
;
5678 tls_mode
= TLS_MODE_FAILED
;
5683 if (lmf_pthread_key
== -1) {
5684 ptk
= mono_jit_tls_id
;
5686 /*g_print ("MonoLMF at: %d\n", ptk);*/
5687 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5688 init_tls_failed = 1;
5691 lmf_pthread_key
= ptk
;
5694 if (monothread_key
== -1) {
5695 ptk
= mono_thread_get_tls_key ();
5697 monothread_key
= ptk
;
5698 /*g_print ("thread inited: %d\n", ptk);*/
5700 /*g_print ("thread not inited yet %d\n", ptk);*/
5706 mono_arch_finish_init (void)
5708 setup_tls_access ();
5712 mono_arch_free_jit_tls_data (MonoJitTlsData
*tls
)
5717 mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
, int this_reg
, int this_type
, int vt_reg
)
5719 int this_dreg
= mips_a0
;
5722 this_dreg
= mips_a1
;
5724 /* add the this argument */
5725 if (this_reg
!= -1) {
5727 MONO_INST_NEW (cfg
, this_ins
, OP_MOVE
);
5728 this_ins
->type
= this_type
;
5729 this_ins
->sreg1
= this_reg
;
5730 this_ins
->dreg
= mono_alloc_ireg (cfg
);
5731 mono_bblock_add_inst (cfg
->cbb
, this_ins
);
5732 mono_call_inst_add_outarg_reg (cfg
, inst
, this_ins
->dreg
, this_dreg
, FALSE
);
5737 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
5738 vtarg
->type
= STACK_MP
;
5739 vtarg
->sreg1
= vt_reg
;
5740 vtarg
->dreg
= mono_alloc_ireg (cfg
);
5741 mono_bblock_add_inst (cfg
->cbb
, vtarg
);
5742 mono_call_inst_add_outarg_reg (cfg
, inst
, vtarg
->dreg
, mips_a0
, FALSE
);
5747 mono_arch_get_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
5749 MonoInst
*ins
= NULL
;
5755 mono_arch_emit_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
5761 mono_arch_print_tree (MonoInst
*tree
, int arity
)
5767 mono_arch_context_get_int_reg (MonoContext
*ctx
, int reg
)
5769 return ctx
->sc_regs
[reg
];
5772 #define ENABLE_WRONG_METHOD_CHECK 0
5774 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5775 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5777 #define LOADSTORE_SIZE 4
5778 #define JUMP_IMM_SIZE 16
5779 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5780 #define LOAD_CONST_SIZE 8
5781 #define JUMP_JR_SIZE 8
5784 * LOCKING: called with the domain lock held
5787 mono_arch_build_imt_trampoline (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
,
5788 gpointer fail_tramp
)
5792 guint8
*code
, *start
, *patch
;
5794 for (i
= 0; i
< count
; ++i
) {
5795 MonoIMTCheckItem
*item
= imt_entries
[i
];
5797 if (item
->is_equals
) {
5798 if (item
->check_target_idx
) {
5799 item
->chunk_size
+= LOAD_CONST_SIZE
+ BR_SIZE
+ JUMP_JR_SIZE
;
5800 if (item
->has_target_code
)
5801 item
->chunk_size
+= LOAD_CONST_SIZE
;
5803 item
->chunk_size
+= LOADSTORE_SIZE
;
5806 item
->chunk_size
+= LOAD_CONST_SIZE
+ BR_SIZE
+ JUMP_IMM32_SIZE
+
5807 LOADSTORE_SIZE
+ JUMP_IMM32_SIZE
;
5808 if (!item
->has_target_code
)
5809 item
->chunk_size
+= LOADSTORE_SIZE
;
5811 item
->chunk_size
+= LOADSTORE_SIZE
+ JUMP_JR_SIZE
;
5812 #if ENABLE_WRONG_METHOD_CHECK
5813 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
+ 4;
5818 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
;
5819 imt_entries
[item
->check_target_idx
]->compare_done
= TRUE
;
5821 size
+= item
->chunk_size
;
5823 /* the initial load of the vtable address */
5824 size
+= MIPS_LOAD_SEQUENCE_LENGTH
;
5826 code
= mono_method_alloc_generic_virtual_trampoline (domain
, size
);
5828 code
= mono_domain_code_reserve (domain
, size
);
5832 /* t7 points to the vtable */
5833 mips_load_const (code
, mips_t7
, (gsize
)(& (vtable
->vtable
[0])));
5835 for (i
= 0; i
< count
; ++i
) {
5836 MonoIMTCheckItem
*item
= imt_entries
[i
];
5838 item
->code_target
= code
;
5839 if (item
->is_equals
) {
5840 if (item
->check_target_idx
) {
5841 mips_load_const (code
, mips_temp
, (gsize
)item
->key
);
5842 item
->jmp_code
= code
;
5843 mips_bne (code
, mips_temp
, MONO_ARCH_IMT_REG
, 0);
5845 if (item
->has_target_code
) {
5846 mips_load_const (code
, mips_t9
,
5847 item
->value
.target_code
);
5850 mips_lw (code
, mips_t9
, mips_t7
,
5851 (sizeof (gpointer
) * item
->value
.vtable_slot
));
5853 mips_jr (code
, mips_t9
);
5857 mips_load_const (code
, mips_temp
, (gsize
)item
->key
);
5859 mips_bne (code
, mips_temp
, MONO_ARCH_IMT_REG
, 0);
5861 if (item
->has_target_code
) {
5862 mips_load_const (code
, mips_t9
,
5863 item
->value
.target_code
);
5866 mips_load_const (code
, mips_at
,
5867 & (vtable
->vtable
[item
->value
.vtable_slot
]));
5868 mips_lw (code
, mips_t9
, mips_at
, 0);
5870 mips_jr (code
, mips_t9
);
5872 mips_patch ((guint32
*)(void *)patch
, (guint32
)code
);
5873 mips_load_const (code
, mips_t9
, fail_tramp
);
5874 mips_jr (code
, mips_t9
);
5877 /* enable the commented code to assert on wrong method */
5878 #if ENABLE_WRONG_METHOD_CHECK
5879 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5880 ppc_compare_log (code
, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5882 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5884 mips_lw (code
, mips_t9
, mips_t7
,
5885 (sizeof (gpointer
) * item
->value
.vtable_slot
));
5886 mips_jr (code
, mips_t9
);
5889 #if ENABLE_WRONG_METHOD_CHECK
5890 ppc_patch (patch
, code
);
5896 mips_load_const (code
, mips_temp
, (gulong
)item
->key
);
5897 mips_slt (code
, mips_temp
, MONO_ARCH_IMT_REG
, mips_temp
);
5899 item
->jmp_code
= code
;
5900 mips_beq (code
, mips_temp
, mips_zero
, 0);
5904 /* patch the branches to get to the target items */
5905 for (i
= 0; i
< count
; ++i
) {
5906 MonoIMTCheckItem
*item
= imt_entries
[i
];
5907 if (item
->jmp_code
&& item
->check_target_idx
) {
5908 mips_patch ((guint32
*)item
->jmp_code
,
5909 (guint32
)imt_entries
[item
->check_target_idx
]->code_target
);
5914 mono_stats
.imt_trampolines_size
+= code
- start
;
5915 g_assert (code
- start
<= size
);
5916 mono_arch_flush_icache (start
, size
);
5918 mono_tramp_info_register (mono_tramp_info_create (NULL
, start
, code
- start
, NULL
, NULL
), domain
);
5924 mono_arch_find_imt_method (mgreg_t
*regs
, guint8
*code
)
5926 return (MonoMethod
*) regs
[MONO_ARCH_IMT_REG
];
5930 mono_arch_find_static_call_vtable (mgreg_t
*regs
, guint8
*code
)
5932 return (MonoVTable
*) regs
[MONO_ARCH_RGCTX_REG
];
5935 /* Soft Debug support */
5936 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5939 * mono_arch_set_breakpoint:
5941 * See mini-amd64.c for docs.
5944 mono_arch_set_breakpoint (MonoJitInfo
*ji
, guint8
*ip
)
5947 guint32 addr
= (guint32
)bp_trigger_page
;
5949 mips_load_const (code
, mips_t9
, addr
);
5950 mips_lw (code
, mips_t9
, mips_t9
, 0);
5952 mono_arch_flush_icache (ip
, code
- ip
);
5956 * mono_arch_clear_breakpoint:
5958 * See mini-amd64.c for docs.
5961 mono_arch_clear_breakpoint (MonoJitInfo
*ji
, guint8
*ip
)
5969 mono_arch_flush_icache (ip
, code
- ip
);
5973 * mono_arch_start_single_stepping:
5975 * See mini-amd64.c for docs.
5978 mono_arch_start_single_stepping (void)
5980 mono_mprotect (ss_trigger_page
, mono_pagesize (), 0);
5984 * mono_arch_stop_single_stepping:
5986 * See mini-amd64.c for docs.
5989 mono_arch_stop_single_stepping (void)
5991 mono_mprotect (ss_trigger_page
, mono_pagesize (), MONO_MMAP_READ
);
5995 * mono_arch_is_single_step_event:
5997 * See mini-amd64.c for docs.
6000 mono_arch_is_single_step_event (void *info
, void *sigctx
)
6002 siginfo_t
* sinfo
= (siginfo_t
*) info
;
6003 /* Sometimes the address is off by 4 */
6004 if (sinfo
->si_addr
>= ss_trigger_page
&& (guint8
*)sinfo
->si_addr
<= (guint8
*)ss_trigger_page
+ 128)
6011 * mono_arch_is_breakpoint_event:
6013 * See mini-amd64.c for docs.
6016 mono_arch_is_breakpoint_event (void *info
, void *sigctx
)
6018 siginfo_t
* sinfo
= (siginfo_t
*) info
;
6019 /* Sometimes the address is off by 4 */
6020 if (sinfo
->si_addr
>= bp_trigger_page
&& (guint8
*)sinfo
->si_addr
<= (guint8
*)bp_trigger_page
+ 128)
6027 * mono_arch_skip_breakpoint:
6029 * See mini-amd64.c for docs.
6032 mono_arch_skip_breakpoint (MonoContext
*ctx
, MonoJitInfo
*ji
)
6034 MONO_CONTEXT_SET_IP (ctx
, (guint8
*)MONO_CONTEXT_GET_IP (ctx
) + 4);
6038 * mono_arch_skip_single_step:
6040 * See mini-amd64.c for docs.
6043 mono_arch_skip_single_step (MonoContext
*ctx
)
6045 MONO_CONTEXT_SET_IP (ctx
, (guint8
*)MONO_CONTEXT_GET_IP (ctx
) + 4);
6049 * mono_arch_get_seq_point_info:
6051 * See mini-amd64.c for docs.
6054 mono_arch_get_seq_point_info (MonoDomain
*domain
, guint8
*code
)
6061 mono_arch_init_lmf_ext (MonoLMFExt
*ext
, gpointer prev_lmf
)
6063 ext
->lmf
.previous_lmf
= prev_lmf
;
6064 /* Mark that this is a MonoLMFExt */
6065 ext
->lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
->lmf
.previous_lmf
) | 2);
6066 ext
->lmf
.iregs
[mips_sp
] = (gssize
)ext
;
6069 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
6072 mono_arch_opcode_supported (int opcode
)