2 * mini-mips.c: MIPS backend for the Mono code generator
5 * Mark Mason (mason@broadcom.com)
7 * Based on mini-ppc.c by
8 * Paolo Molaro (lupus@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2003 Ximian, Inc.
16 #include <asm/cachectl.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
21 #include <mono/arch/mips/mips-codegen.h>
23 #include "mini-mips.h"
28 #define SAVE_FP_REGS 0
29 #define SAVE_ALL_REGS 0
30 #define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
31 #define LONG_BRANCH 1 /* needed for yyparse in mcs */
34 #define ALWAYS_USE_FP 1
35 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
37 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
38 #define USE_MUL 1 /* use mul instead of mult/mflo for multiply */
47 /* This mutex protects architecture specific caches */
48 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
49 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
50 static CRITICAL_SECTION mini_arch_mutex
;
52 int mono_exc_esp_offset
= 0;
53 static int tls_mode
= TLS_MODE_DETECT
;
54 static int lmf_pthread_key
= -1;
55 static int monothread_key
= -1;
56 static int monodomain_key
= -1;
59 #define DEBUG(a) if (cfg->verbose_level > 1) a
65 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
67 code = mips_emit_exc_by_name (code, exc_name); \
68 cfg->bb_exit->max_offset += 16; \
72 #define emit_linuxthreads_tls(code,dreg,key) do {\
74 off1 = offsets_from_pthread_key ((key), &off2); \
75 g_assert_not_reached (); \
76 ppc_lwz ((code), (dreg), off1, ppc_r2); \
77 ppc_lwz ((code), (dreg), off2, (dreg)); \
81 #define emit_tls_access(code,dreg,key) do { \
83 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
84 default: g_assert_not_reached (); \
88 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
90 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
91 inst->type = STACK_R8; \
93 inst->inst_p0 = (void*)(addr); \
94 mono_bblock_add_inst (cfg->cbb, inst); \
97 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
98 || ((ins)->opcode == OP_ICOMPARE) \
99 || ((ins)->opcode == OP_LCOMPARE)))
100 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
101 || ((ins)->opcode == OP_ICOMPARE_IMM) \
102 || ((ins)->opcode == OP_LCOMPARE_IMM)))
104 #define INS_REWRITE(ins, op, _s1, _s2) do { \
107 ins->opcode = (op); \
112 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
114 ins->opcode = (op); \
116 ins->inst_imm = (_imm); \
120 typedef struct InstList InstList
;
138 guint16 vtsize
; /* in param area */
140 guint8 regtype
: 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
141 guint8 size
: 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
158 void patch_lui_addiu(guint32
*ip
, guint32 val
);
159 guint8
*mono_arch_emit_epilog_sub (MonoCompile
*cfg
, guint8
*code
);
160 guint8
*mips_emit_cond_branch (MonoCompile
*cfg
, guint8
*code
, int op
, MonoInst
*ins
);
161 void mips_adjust_stackframe(MonoCompile
*cfg
);
162 void mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
, int this_reg
, int this_type
, int vt_reg
);
163 MonoInst
*mono_arch_get_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
);
167 mono_arch_flush_icache (guint8
*code
, gint size
)
169 /* Linux/MIPS specific */
170 cacheflush (code
, size
, BCACHE
);
174 mono_arch_flush_register_windows (void)
179 mono_arch_is_inst_imm (gint64 imm
)
185 mips_emit_exc_by_name(guint8
*code
, const char *name
)
188 MonoClass
*exc_class
;
190 exc_class
= mono_class_from_name (mono_defaults
.corlib
, "System", name
);
191 g_assert (exc_class
);
193 mips_load_const (code
, mips_a0
, exc_class
->type_token
);
194 addr
= (guint32
) mono_get_throw_corlib_exception ();
195 mips_load_const (code
, mips_t9
, addr
);
196 mips_jalr (code
, mips_t9
, mips_ra
);
204 mips_emit_load_const(guint8
*code
, int dreg
, mgreg_t v
)
206 if (mips_is_imm16 (v
))
207 mips_addiu (code
, dreg
, mips_zero
, ((guint32
)v
) & 0xffff);
209 #if SIZEOF_REGISTER == 8
211 /* v is not a sign-extended 32-bit value */
212 mips_lui (code
, dreg
, mips_zero
, (guint32
)((v
>> (32+16)) & 0xffff));
213 mips_ori (code
, dreg
, dreg
, (guint32
)((v
>> (32)) & 0xffff));
214 mips_dsll (code
, dreg
, dreg
, 16);
215 mips_ori (code
, dreg
, dreg
, (guint32
)((v
>> (16)) & 0xffff));
216 mips_dsll (code
, dreg
, dreg
, 16);
217 mips_ori (code
, dreg
, dreg
, (guint32
)(v
& 0xffff));
221 if (((guint32
)v
) & (1 << 15)) {
222 mips_lui (code
, dreg
, mips_zero
, (((guint32
)v
)>>16)+1);
225 mips_lui (code
, dreg
, mips_zero
, (((guint32
)v
)>>16));
227 if (((guint32
)v
) & 0xffff)
228 mips_addiu (code
, dreg
, dreg
, ((guint32
)v
) & 0xffff);
234 mips_emit_cond_branch (MonoCompile
*cfg
, guint8
*code
, int op
, MonoInst
*ins
)
242 /* Invert test and emit branch around jump */
245 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, br_offset
);
249 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, br_offset
);
253 mips_bltz (code
, ins
->sreg1
, br_offset
);
257 mips_blez (code
, ins
->sreg1
, br_offset
);
261 mips_bgtz (code
, ins
->sreg1
, br_offset
);
265 mips_bgez (code
, ins
->sreg1
, br_offset
);
269 g_assert_not_reached ();
271 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
272 MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
273 mips_lui (code
, mips_at
, mips_zero
, 0);
274 mips_addiu (code
, mips_at
, mips_at
, 0);
275 mips_jr (code
, mips_at
);
278 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
279 MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
282 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, 0);
286 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, 0);
290 mips_bgez (code
, ins
->sreg1
, 0);
294 mips_bgtz (code
, ins
->sreg1
, 0);
298 mips_blez (code
, ins
->sreg1
, 0);
302 mips_bltz (code
, ins
->sreg1
, 0);
306 g_assert_not_reached ();
312 /* XXX - big-endian dependent? */
314 patch_lui_addiu(guint32
*ip
, guint32 val
)
316 guint16
*__lui_addiu
= (guint16
*)(void *)(ip
);
319 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
320 ip
, ((guint32
*)ip
)[0], ((guint32
*)ip
)[1], val
);
323 if (((guint32
)(val
)) & (1 << 15))
324 __lui_addiu
[MINI_LS_WORD_IDX
] = ((((guint32
)(val
)) >> 16) & 0xffff) + 1;
326 __lui_addiu
[MINI_LS_WORD_IDX
] = (((guint32
)(val
)) >> 16) & 0xffff;
327 __lui_addiu
[MINI_LS_WORD_IDX
+ 2] = ((guint32
)(val
)) & 0xffff;
328 mono_arch_flush_icache ((guint8
*)ip
, 8);
333 mips_patch (guint32
*code
, guint32 target
)
336 guint32 op
= ins
>> 26;
337 guint32 diff
, offset
;
339 g_assert (trap_target
!= target
);
340 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
342 case 0x00: /* jr ra */
343 if (ins
== 0x3e00008)
345 g_assert_not_reached ();
349 g_assert (!(target
& 0x03));
350 g_assert ((target
& 0xfc000000) == (((guint32
)code
) & 0xfc000000));
351 ins
= (ins
& 0xfc000000) | (((target
) >> 2) & 0x03ffffff);
353 mono_arch_flush_icache ((guint8
*)code
, 4);
355 case 0x01: /* BLTZ */
358 case 0x06: /* BLEZ */
359 case 0x07: /* BGTZ */
360 case 0x11: /* bc1t */
361 diff
= target
- (guint32
)(code
+ 1);
362 g_assert (((diff
& 0x0003ffff) == diff
) || ((diff
| 0xfffc0000) == diff
));
363 g_assert (!(diff
& 0x03));
364 offset
= ((gint32
)diff
) >> 2;
365 g_assert (((int)offset
) == ((int)(short)offset
));
366 ins
= (ins
& 0xffff0000) | (offset
& 0x0000ffff);
368 mono_arch_flush_icache ((guint8
*)code
, 4);
370 case 0x0f: /* LUI / ADDIU pair */
371 patch_lui_addiu (code
, target
);
372 mono_arch_flush_icache ((guint8
*)code
, 8);
376 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op
, ins
, code
);
377 g_assert_not_reached ();
383 offsets_from_pthread_key (guint32 key
, int *offset2
)
387 *offset2
= idx2
* sizeof (gpointer
);
388 return 284 + idx1
* sizeof (gpointer
);
393 mono_arch_regname (int reg
) {
394 #if _MIPS_SIM == _ABIO32
395 static const char * rnames
[] = {
396 "zero", "at", "v0", "v1",
397 "a0", "a1", "a2", "a3",
398 "t0", "t1", "t2", "t3",
399 "t4", "t5", "t6", "t7",
400 "s0", "s1", "s2", "s3",
401 "s4", "s5", "s6", "s7",
402 "t8", "t9", "k0", "k1",
403 "gp", "sp", "fp", "ra"
405 #elif _MIPS_SIM == _ABIN32
406 static const char * rnames
[] = {
407 "zero", "at", "v0", "v1",
408 "a0", "a1", "a2", "a3",
409 "a4", "a5", "a6", "a7",
410 "t0", "t1", "t2", "t3",
411 "s0", "s1", "s2", "s3",
412 "s4", "s5", "s6", "s7",
413 "t8", "t9", "k0", "k1",
414 "gp", "sp", "fp", "ra"
417 if (reg
>= 0 && reg
< 32)
423 mono_arch_fregname (int reg
) {
424 static const char * rnames
[] = {
425 "f0", "f1", "f2", "f3",
426 "f4", "f5", "f6", "f7",
427 "f8", "f9", "f10", "f11",
428 "f12", "f13", "f14", "f15",
429 "f16", "f17", "f18", "f19",
430 "f20", "f21", "f22", "f23",
431 "f24", "f25", "f26", "f27",
432 "f28", "f29", "f30", "f31"
434 if (reg
>= 0 && reg
< 32)
439 /* this function overwrites at */
441 emit_memcpy (guint8
*code
, int size
, int dreg
, int doffset
, int sreg
, int soffset
)
443 /* XXX write a loop, not an unrolled loop */
445 mips_lw (code
, mips_at
, sreg
, soffset
);
446 mips_sw (code
, mips_at
, dreg
, doffset
);
455 * mono_arch_get_argument_info:
456 * @csig: a method signature
457 * @param_count: the number of parameters to consider
458 * @arg_info: an array to store the result infos
460 * Gathers information on parameters such as size, alignment and
461 * padding. arg_info should be large enought to hold param_count + 1 entries.
463 * Returns the size of the activation frame.
466 mono_arch_get_argument_info (MonoMethodSignature
*csig
, int param_count
, MonoJitArgumentInfo
*arg_info
)
468 int k
, frame_size
= 0;
469 guint32 size
, align
, pad
;
472 if (MONO_TYPE_ISSTRUCT (csig
->ret
)) {
473 frame_size
+= sizeof (gpointer
);
477 arg_info
[0].offset
= offset
;
480 frame_size
+= sizeof (gpointer
);
484 arg_info
[0].size
= frame_size
;
486 for (k
= 0; k
< param_count
; k
++) {
487 size
= mini_type_stack_size_full (NULL
, csig
->params
[k
], &align
, csig
->pinvoke
);
489 /* ignore alignment for now */
492 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
493 arg_info
[k
].pad
= pad
;
495 arg_info
[k
+ 1].pad
= 0;
496 arg_info
[k
+ 1].size
= size
;
498 arg_info
[k
+ 1].offset
= offset
;
502 align
= MONO_ARCH_FRAME_ALIGNMENT
;
503 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
504 arg_info
[k
].pad
= pad
;
511 mono_arch_get_this_arg_from_call (MonoGenericSharingContext
*gsctx
, MonoMethodSignature
*sig
, mgreg_t
*regs
, guint8
*code
)
513 /* FIXME: handle returning a struct */
514 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
515 return (gpointer
)regs
[mips_a1
];
516 return (gpointer
)regs
[mips_a0
];
520 * Initialize the cpu to execute managed code.
523 mono_arch_cpu_init (void)
528 * Initialize architecture specific code.
531 mono_arch_init (void)
533 InitializeCriticalSection (&mini_arch_mutex
);
537 * Cleanup architecture specific code.
540 mono_arch_cleanup (void)
542 DeleteCriticalSection (&mini_arch_mutex
);
546 * This function returns the optimizations supported on this cpu.
549 mono_arch_cpu_optimizazions (guint32
*exclude_mask
)
553 /* no mips-specific optimizations yet */
559 is_regsize_var (MonoType
*t
) {
562 t
= mono_type_get_underlying_type (t
);
566 #if (SIZEOF_REGISTER == 8)
573 case MONO_TYPE_FNPTR
:
575 case MONO_TYPE_OBJECT
:
576 case MONO_TYPE_STRING
:
577 case MONO_TYPE_CLASS
:
578 case MONO_TYPE_SZARRAY
:
579 case MONO_TYPE_ARRAY
:
581 case MONO_TYPE_GENERICINST
:
582 if (!mono_type_generic_inst_is_valuetype (t
))
585 case MONO_TYPE_VALUETYPE
:
592 mono_arch_get_allocatable_int_vars (MonoCompile
*cfg
)
597 for (i
= 0; i
< cfg
->num_varinfo
; i
++) {
598 MonoInst
*ins
= cfg
->varinfo
[i
];
599 MonoMethodVar
*vmv
= MONO_VARINFO (cfg
, i
);
602 if (vmv
->range
.first_use
.abs_pos
>= vmv
->range
.last_use
.abs_pos
)
605 if (ins
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
) || (ins
->opcode
!= OP_LOCAL
&& ins
->opcode
!= OP_ARG
))
608 /* we can only allocate 32 bit values */
609 if (is_regsize_var (ins
->inst_vtype
)) {
610 g_assert (MONO_VARINFO (cfg
, i
)->reg
== -1);
611 g_assert (i
== vmv
->idx
);
612 vars
= mono_varlist_insert_sorted (cfg
, vars
, vmv
, FALSE
);
620 mono_arch_get_global_int_regs (MonoCompile
*cfg
)
624 regs
= g_list_prepend (regs
, (gpointer
)mips_s0
);
625 regs
= g_list_prepend (regs
, (gpointer
)mips_s1
);
626 regs
= g_list_prepend (regs
, (gpointer
)mips_s2
);
627 regs
= g_list_prepend (regs
, (gpointer
)mips_s3
);
628 regs
= g_list_prepend (regs
, (gpointer
)mips_s4
);
629 //regs = g_list_prepend (regs, (gpointer)mips_s5);
630 regs
= g_list_prepend (regs
, (gpointer
)mips_s6
);
631 regs
= g_list_prepend (regs
, (gpointer
)mips_s7
);
637 * mono_arch_regalloc_cost:
639 * Return the cost, in number of memory references, of the action of
640 * allocating the variable VMV into a register during global register
644 mono_arch_regalloc_cost (MonoCompile
*cfg
, MonoMethodVar
*vmv
)
651 args_onto_stack (CallInfo
*info
)
653 g_assert (!info
->on_stack
);
654 g_assert (info
->stack_size
<= MIPS_STACK_PARAM_OFFSET
);
655 info
->on_stack
= TRUE
;
656 info
->stack_size
= MIPS_STACK_PARAM_OFFSET
;
659 #if _MIPS_SIM == _ABIO32
661 * O32 calling convention version
665 add_int32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
666 /* First, see if we need to drop onto the stack */
667 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
668 args_onto_stack (info
);
670 /* Now, place the argument */
671 if (info
->on_stack
) {
672 ainfo
->regtype
= RegTypeBase
;
673 ainfo
->reg
= mips_sp
; /* in the caller */
674 ainfo
->offset
= info
->stack_size
;
677 ainfo
->regtype
= RegTypeGeneral
;
678 ainfo
->reg
= info
->gr
;
680 info
->gr_passed
= TRUE
;
682 info
->stack_size
+= 4;
686 add_int64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
687 /* First, see if we need to drop onto the stack */
688 if (!info
->on_stack
&& info
->gr
+1 > MIPS_LAST_ARG_REG
)
689 args_onto_stack (info
);
691 /* Now, place the argument */
692 if (info
->on_stack
) {
693 g_assert (info
->stack_size
% 4 == 0);
694 info
->stack_size
+= (info
->stack_size
% 8);
696 ainfo
->regtype
= RegTypeBase
;
697 ainfo
->reg
= mips_sp
; /* in the caller */
698 ainfo
->offset
= info
->stack_size
;
701 // info->gr must be a0 or a2
702 info
->gr
+= (info
->gr
- MIPS_FIRST_ARG_REG
) % 2;
703 g_assert(info
->gr
<= MIPS_LAST_ARG_REG
);
705 ainfo
->regtype
= RegTypeGeneral
;
706 ainfo
->reg
= info
->gr
;
708 info
->gr_passed
= TRUE
;
710 info
->stack_size
+= 8;
714 add_float32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
715 /* First, see if we need to drop onto the stack */
716 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
717 args_onto_stack (info
);
719 /* Now, place the argument */
720 if (info
->on_stack
) {
721 ainfo
->regtype
= RegTypeBase
;
722 ainfo
->reg
= mips_sp
; /* in the caller */
723 ainfo
->offset
= info
->stack_size
;
726 /* Only use FP regs for args if no int args passed yet */
727 if (!info
->gr_passed
&& info
->fr
<= MIPS_LAST_FPARG_REG
) {
728 ainfo
->regtype
= RegTypeFP
;
729 ainfo
->reg
= info
->fr
;
730 /* Even though it's a single-precision float, it takes up two FP regs */
732 /* FP and GP slots do not overlap */
736 /* Passing single-precision float arg in a GP register
737 * such as: func (0, 1.0, 2, 3);
738 * In this case, only one 'gr' register is consumed.
740 ainfo
->regtype
= RegTypeGeneral
;
741 ainfo
->reg
= info
->gr
;
744 info
->gr_passed
= TRUE
;
747 info
->stack_size
+= 4;
751 add_float64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
752 /* First, see if we need to drop onto the stack */
753 if (!info
->on_stack
&& info
->gr
+1 > MIPS_LAST_ARG_REG
)
754 args_onto_stack (info
);
756 /* Now, place the argument */
757 if (info
->on_stack
) {
758 g_assert(info
->stack_size
% 4 == 0);
759 info
->stack_size
+= (info
->stack_size
% 8);
761 ainfo
->regtype
= RegTypeBase
;
762 ainfo
->reg
= mips_sp
; /* in the caller */
763 ainfo
->offset
= info
->stack_size
;
766 /* Only use FP regs for args if no int args passed yet */
767 if (!info
->gr_passed
&& info
->fr
<= MIPS_LAST_FPARG_REG
) {
768 ainfo
->regtype
= RegTypeFP
;
769 ainfo
->reg
= info
->fr
;
771 /* FP and GP slots do not overlap */
775 // info->gr must be a0 or a2
776 info
->gr
+= (info
->gr
- MIPS_FIRST_ARG_REG
) % 2;
777 g_assert(info
->gr
<= MIPS_LAST_ARG_REG
);
779 ainfo
->regtype
= RegTypeGeneral
;
780 ainfo
->reg
= info
->gr
;
782 info
->gr_passed
= TRUE
;
785 info
->stack_size
+= 8;
787 #elif _MIPS_SIM == _ABIN32
789 * N32 calling convention version
793 add_int32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
794 /* First, see if we need to drop onto the stack */
795 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
796 args_onto_stack (info
);
798 /* Now, place the argument */
799 if (info
->on_stack
) {
800 ainfo
->regtype
= RegTypeBase
;
801 ainfo
->reg
= mips_sp
; /* in the caller */
802 ainfo
->offset
= info
->stack_size
;
803 info
->stack_size
+= SIZEOF_REGISTER
;
806 ainfo
->regtype
= RegTypeGeneral
;
807 ainfo
->reg
= info
->gr
;
809 info
->gr_passed
= TRUE
;
814 add_int64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
815 /* First, see if we need to drop onto the stack */
816 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
817 args_onto_stack (info
);
819 /* Now, place the argument */
820 if (info
->on_stack
) {
821 g_assert (info
->stack_size
% 4 == 0);
822 info
->stack_size
+= (info
->stack_size
% 8);
824 ainfo
->regtype
= RegTypeBase
;
825 ainfo
->reg
= mips_sp
; /* in the caller */
826 ainfo
->offset
= info
->stack_size
;
827 info
->stack_size
+= SIZEOF_REGISTER
;
830 g_assert (info
->gr
<= MIPS_LAST_ARG_REG
);
832 ainfo
->regtype
= RegTypeGeneral
;
833 ainfo
->reg
= info
->gr
;
835 info
->gr_passed
= TRUE
;
840 add_float32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
841 /* First, see if we need to drop onto the stack */
842 if (!info
->on_stack
) {
843 if (info
->gr
> MIPS_LAST_ARG_REG
)
844 args_onto_stack (info
);
845 else if (info
->fr
> MIPS_LAST_FPARG_REG
)
846 args_onto_stack (info
);
849 /* Now, place the argument */
850 if (info
->on_stack
) {
851 ainfo
->regtype
= RegTypeBase
;
852 ainfo
->reg
= mips_sp
; /* in the caller */
853 ainfo
->offset
= info
->stack_size
;
854 info
->stack_size
+= FREG_SIZE
;
857 ainfo
->regtype
= RegTypeFP
;
858 ainfo
->reg
= info
->fr
;
860 /* FP and GP slots do not overlap */
866 add_float64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
867 /* First, see if we need to drop onto the stack */
868 if (!info
->on_stack
) {
869 if (info
->gr
> MIPS_LAST_ARG_REG
)
870 args_onto_stack (info
);
871 else if (info
->fr
> MIPS_LAST_FPARG_REG
)
872 args_onto_stack (info
);
875 /* Now, place the argument */
876 if (info
->on_stack
) {
877 g_assert(info
->stack_size
% 4 == 0);
878 info
->stack_size
+= (info
->stack_size
% 8);
880 ainfo
->regtype
= RegTypeBase
;
881 ainfo
->reg
= mips_sp
; /* in the caller */
882 ainfo
->offset
= info
->stack_size
;
883 info
->stack_size
+= FREG_SIZE
;
886 ainfo
->regtype
= RegTypeFP
;
887 ainfo
->reg
= info
->fr
;
889 /* FP and GP slots do not overlap */
896 calculate_sizes (MonoMethodSignature
*sig
, gboolean is_pinvoke
)
899 int n
= sig
->hasthis
+ sig
->param_count
;
900 MonoType
* simpletype
;
901 CallInfo
*cinfo
= g_malloc0 (sizeof (CallInfo
) + sizeof (ArgInfo
) * n
);
903 cinfo
->fr
= MIPS_FIRST_FPARG_REG
;
904 cinfo
->gr
= MIPS_FIRST_ARG_REG
;
905 cinfo
->stack_size
= 0;
907 DEBUG(printf("calculate_sizes\n"));
909 /* handle returning a struct */
910 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
911 cinfo
->struct_ret
= cinfo
->gr
;
912 add_int32_arg (cinfo
, &cinfo
->ret
);
917 add_int32_arg (cinfo
, cinfo
->args
+ n
);
920 DEBUG(printf("params: %d\n", sig
->param_count
));
921 for (i
= 0; i
< sig
->param_count
; ++i
) {
922 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
923 /* Prevent implicit arguments and sig_cookie from
924 being passed in registers */
925 args_onto_stack (cinfo
);
926 /* Emit the signature cookie just before the implicit arguments */
927 add_int32_arg (cinfo
, &cinfo
->sig_cookie
);
929 DEBUG(printf("param %d: ", i
));
930 if (sig
->params
[i
]->byref
) {
931 DEBUG(printf("byref\n"));
932 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
936 simpletype
= mono_type_get_underlying_type (sig
->params
[i
]);
937 switch (simpletype
->type
) {
938 case MONO_TYPE_BOOLEAN
:
941 DEBUG(printf("1 byte\n"));
942 cinfo
->args
[n
].size
= 1;
943 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
949 DEBUG(printf("2 bytes\n"));
950 cinfo
->args
[n
].size
= 2;
951 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
956 DEBUG(printf("4 bytes\n"));
957 cinfo
->args
[n
].size
= 4;
958 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
964 case MONO_TYPE_FNPTR
:
965 case MONO_TYPE_CLASS
:
966 case MONO_TYPE_OBJECT
:
967 case MONO_TYPE_STRING
:
968 case MONO_TYPE_SZARRAY
:
969 case MONO_TYPE_ARRAY
:
970 cinfo
->args
[n
].size
= sizeof (gpointer
);
971 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
974 case MONO_TYPE_GENERICINST
:
975 if (!mono_type_generic_inst_is_valuetype (simpletype
)) {
976 cinfo
->args
[n
].size
= sizeof (gpointer
);
977 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
982 case MONO_TYPE_VALUETYPE
: {
985 int has_offset
= FALSE
;
987 gint size
, alignment
;
990 klass
= mono_class_from_mono_type (sig
->params
[i
]);
992 size
= mono_class_native_size (klass
, NULL
);
994 size
= mono_class_value_size (klass
, NULL
);
995 alignment
= mono_class_min_align (klass
);
996 #if MIPS_PASS_STRUCTS_BY_VALUE
997 /* Need to do alignment if struct contains long or double */
999 if (cinfo
->stack_size
& (alignment
- 1)) {
1000 add_int32_arg (cinfo
, &dummy_arg
);
1002 g_assert (!(cinfo
->stack_size
& (alignment
- 1)));
1006 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1007 mono_class_native_size (sig
->params
[i
]->data
.klass
, NULL
),
1008 cinfo
->stack_size
, alignment
);
1010 nwords
= (size
+ sizeof (gpointer
) -1 ) / sizeof (gpointer
);
1011 g_assert (cinfo
->args
[n
].size
== 0);
1012 g_assert (cinfo
->args
[n
].vtsize
== 0);
1013 for (j
= 0; j
< nwords
; ++j
) {
1015 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1016 if (cinfo
->on_stack
)
1019 add_int32_arg (cinfo
, &dummy_arg
);
1020 if (!has_offset
&& cinfo
->on_stack
) {
1021 cinfo
->args
[n
].offset
= dummy_arg
.offset
;
1025 if (cinfo
->on_stack
)
1026 cinfo
->args
[n
].vtsize
+= 1;
1028 cinfo
->args
[n
].size
+= 1;
1030 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1031 cinfo
->args
[n
].regtype
= RegTypeStructByVal
;
1033 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1034 cinfo
->args
[n
].regtype
= RegTypeStructByAddr
;
1039 case MONO_TYPE_TYPEDBYREF
: {
1040 /* keep in sync or merge with the valuetype case */
1041 #if MIPS_PASS_STRUCTS_BY_VALUE
1043 int size
= sizeof (MonoTypedRef
);
1044 int nwords
= (size
+ sizeof (gpointer
) -1 ) / sizeof (gpointer
);
1045 cinfo
->args
[n
].regtype
= RegTypeStructByVal
;
1046 if (!cinfo
->on_stack
&& cinfo
->gr
<= MIPS_LAST_ARG_REG
) {
1047 int rest
= MIPS_LAST_ARG_REG
- cinfo
->gr
+ 1;
1048 int n_in_regs
= rest
>= nwords
? nwords
: rest
;
1049 cinfo
->args
[n
].size
= n_in_regs
;
1050 cinfo
->args
[n
].vtsize
= nwords
- n_in_regs
;
1051 cinfo
->args
[n
].reg
= cinfo
->gr
;
1052 cinfo
->gr
+= n_in_regs
;
1053 cinfo
->gr_passed
= TRUE
;
1055 cinfo
->args
[n
].size
= 0;
1056 cinfo
->args
[n
].vtsize
= nwords
;
1058 if (cinfo
->args
[n
].vtsize
> 0) {
1059 if (!cinfo
->on_stack
)
1060 args_onto_stack (cinfo
);
1061 g_assert(cinfo
->on_stack
);
1062 cinfo
->args
[n
].offset
= cinfo
->stack_size
;
1063 g_print ("offset for arg %d at %d\n", n
, cinfo
->args
[n
].offset
);
1064 cinfo
->stack_size
+= cinfo
->args
[n
].vtsize
* sizeof (gpointer
);
1068 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1069 cinfo
->args
[n
].regtype
= RegTypeStructByAddr
;
1076 DEBUG(printf("8 bytes\n"));
1077 cinfo
->args
[n
].size
= 8;
1078 add_int64_arg (cinfo
, &cinfo
->args
[n
]);
1082 DEBUG(printf("R4\n"));
1083 cinfo
->args
[n
].size
= 4;
1084 add_float32_arg (cinfo
, &cinfo
->args
[n
]);
1088 DEBUG(printf("R8\n"));
1089 cinfo
->args
[n
].size
= 8;
1090 add_float64_arg (cinfo
, &cinfo
->args
[n
]);
1094 g_error ("Can't trampoline 0x%x", sig
->params
[i
]->type
);
1099 simpletype
= mono_type_get_underlying_type (sig
->ret
);
1100 switch (simpletype
->type
) {
1101 case MONO_TYPE_BOOLEAN
:
1106 case MONO_TYPE_CHAR
:
1112 case MONO_TYPE_FNPTR
:
1113 case MONO_TYPE_CLASS
:
1114 case MONO_TYPE_OBJECT
:
1115 case MONO_TYPE_SZARRAY
:
1116 case MONO_TYPE_ARRAY
:
1117 case MONO_TYPE_STRING
:
1118 cinfo
->ret
.reg
= mips_v0
;
1122 cinfo
->ret
.reg
= mips_v0
;
1126 cinfo
->ret
.reg
= mips_f0
;
1127 cinfo
->ret
.regtype
= RegTypeFP
;
1129 case MONO_TYPE_GENERICINST
:
1130 if (!mono_type_generic_inst_is_valuetype (simpletype
)) {
1131 cinfo
->ret
.reg
= mips_v0
;
1135 case MONO_TYPE_VALUETYPE
:
1137 case MONO_TYPE_TYPEDBYREF
:
1138 case MONO_TYPE_VOID
:
1141 g_error ("Can't handle as return value 0x%x", sig
->ret
->type
);
1145 /* align stack size to 16 */
1146 cinfo
->stack_size
= (cinfo
->stack_size
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1148 cinfo
->stack_usage
= cinfo
->stack_size
;
1154 * Set var information according to the calling convention. mips version.
1155 * The locals var stuff should most likely be split in another method.
1158 mono_arch_allocate_vars (MonoCompile
*cfg
)
1160 MonoMethodSignature
*sig
;
1161 MonoMethodHeader
*header
;
1163 int i
, offset
, size
, align
, curinst
;
1164 int frame_reg
= mips_sp
;
1165 guint32 iregs_to_save
= 0;
1167 guint32 fregs_to_restore
;
1170 /* spill down, we'll fix it in a separate pass */
1171 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1173 /* allow room for the vararg method args: void* and long/double */
1174 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (cfg
->method
))
1175 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (gpointer
)*8);
1177 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1178 * call convs needs to be handled this way.
1180 if (cfg
->flags
& MONO_CFG_HAS_VARARGS
)
1181 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (gpointer
)*8);
1183 /* gtk-sharp and other broken code will dllimport vararg functions even with
1184 * non-varargs signatures. Since there is little hope people will get this right
1185 * we assume they won't.
1187 if (cfg
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
1188 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (gpointer
)*8);
1190 /* a0-a3 always present */
1191 cfg
->param_area
= MAX (cfg
->param_area
, MIPS_STACK_PARAM_OFFSET
);
1193 header
= cfg
->header
;
1195 sig
= mono_method_signature (cfg
->method
);
1198 * We use the frame register also for any method that has
1199 * exception clauses. This way, when the handlers are called,
1200 * the code will reference local variables using the frame reg instead of
1201 * the stack pointer: if we had to restore the stack pointer, we'd
1202 * corrupt the method frames that are already on the stack (since
1203 * filters get called before stack unwinding happens) when the filter
1204 * code would call any method (this also applies to finally etc.).
1207 if ((cfg
->flags
& MONO_CFG_HAS_ALLOCA
) || header
->num_clauses
|| ALWAYS_USE_FP
)
1208 frame_reg
= mips_fp
;
1209 cfg
->frame_reg
= frame_reg
;
1210 if (frame_reg
!= mips_sp
) {
1211 cfg
->used_int_regs
|= 1 << frame_reg
;
1216 if (!MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1217 /* FIXME: handle long and FP values */
1218 switch (mono_type_get_underlying_type (sig
->ret
)->type
) {
1219 case MONO_TYPE_VOID
:
1223 cfg
->ret
->opcode
= OP_REGVAR
;
1224 cfg
->ret
->inst_c0
= cfg
->ret
->dreg
= mips_f0
;
1227 cfg
->ret
->opcode
= OP_REGVAR
;
1228 cfg
->ret
->inst_c0
= mips_v0
;
1232 /* Space for outgoing parameters, including a0-a3 */
1233 offset
+= cfg
->param_area
;
1235 /* allow room to save the return value (if it's a struct) */
1236 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (cfg
->method
))
1239 if (sig
->call_convention
== MONO_CALL_VARARG
) {
1240 cfg
->sig_cookie
= MIPS_STACK_PARAM_OFFSET
;
1243 /* Now handle the local variables */
1245 curinst
= cfg
->locals_start
;
1246 for (i
= curinst
; i
< cfg
->num_varinfo
; ++i
) {
1247 inst
= cfg
->varinfo
[i
];
1248 if ((inst
->flags
& MONO_INST_IS_DEAD
) || inst
->opcode
== OP_REGVAR
)
1251 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1252 * pinvoke wrappers when they call functions returning structure
1254 if (inst
->backend
.is_pinvoke
&& MONO_TYPE_ISSTRUCT (inst
->inst_vtype
) && inst
->inst_vtype
->type
!= MONO_TYPE_TYPEDBYREF
)
1255 size
= mono_class_native_size (mono_class_from_mono_type (inst
->inst_vtype
), (unsigned int *) &align
);
1257 size
= mono_type_size (inst
->inst_vtype
, &align
);
1259 offset
+= align
- 1;
1260 offset
&= ~(align
- 1);
1261 inst
->inst_offset
= offset
;
1262 inst
->opcode
= OP_REGOFFSET
;
1263 inst
->inst_basereg
= frame_reg
;
1265 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1268 /* Space for LMF (if needed) */
1270 if (cfg
->method
->save_lmf
) {
1271 /* align the offset to 16 bytes */
1272 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1273 cfg
->arch
.lmf_offset
= offset
;
1274 offset
+= sizeof (MonoLMF
);
1278 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1279 * args or return vals. Extra stack space avoids this in a lot of cases.
1281 offset
+= EXTRA_STACK_SPACE
;
1283 /* Space for saved registers */
1284 cfg
->arch
.iregs_offset
= offset
;
1286 iregs_to_save
= MONO_ARCH_CALLEE_SAVED_REGS
;
1288 iregs_to_save
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
1290 if (iregs_to_save
) {
1291 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
1292 if (iregs_to_save
& (1 << i
)) {
1293 offset
+= SIZEOF_REGISTER
;
1298 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1299 * args or return vals. Extra stack space avoids this in a lot of cases.
1301 offset
+= EXTRA_STACK_SPACE
;
1303 /* saved float registers */
1305 fregs_to_restore
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
1306 if (fregs_to_restore
) {
1307 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
1308 if (fregs_to_restore
& (1 << i
)) {
1309 offset
+= sizeof(double);
1315 #if _MIPS_SIM == _ABIO32
1316 /* Now add space for saving the ra */
1317 offset
+= SIZEOF_VOID_P
;
1320 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1321 cfg
->stack_offset
= offset
;
1322 cfg
->arch
.local_alloc_offset
= cfg
->stack_offset
;
1326 * Now allocate stack slots for the int arg regs (a0 - a3)
1327 * On MIPS o32, these are just above the incoming stack pointer
1328 * Even if the arg has been assigned to a regvar, it gets a stack slot
1331 /* Return struct-by-value results in a hidden first argument */
1332 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1333 cfg
->vret_addr
->opcode
= OP_REGOFFSET
;
1334 cfg
->vret_addr
->inst_c0
= mips_a0
;
1335 cfg
->vret_addr
->inst_offset
= offset
;
1336 cfg
->vret_addr
->inst_basereg
= frame_reg
;
1337 offset
+= SIZEOF_REGISTER
;
1340 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
1341 inst
= cfg
->args
[i
];
1342 if (inst
->opcode
!= OP_REGVAR
) {
1345 if (sig
->hasthis
&& (i
== 0))
1346 arg_type
= &mono_defaults
.object_class
->byval_arg
;
1348 arg_type
= sig
->params
[i
- sig
->hasthis
];
1350 inst
->opcode
= OP_REGOFFSET
;
1351 size
= mono_type_size (arg_type
, &align
);
1353 if (size
< SIZEOF_REGISTER
) {
1354 size
= SIZEOF_REGISTER
;
1355 align
= SIZEOF_REGISTER
;
1357 inst
->inst_basereg
= frame_reg
;
1358 offset
= (offset
+ align
- 1) & ~(align
- 1);
1359 inst
->inst_offset
= offset
;
1361 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
< sig
->sentinelpos
))
1362 cfg
->sig_cookie
+= size
;
1363 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1366 #if _MIPS_SIM == _ABIO32
1367 /* o32: Even a0-a3 get stack slots */
1368 size
= SIZEOF_REGISTER
;
1369 align
= SIZEOF_REGISTER
;
1370 inst
->inst_basereg
= frame_reg
;
1371 offset
= (offset
+ align
- 1) & ~(align
- 1);
1372 inst
->inst_offset
= offset
;
1374 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
< sig
->sentinelpos
))
1375 cfg
->sig_cookie
+= size
;
1376 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1380 #if _MIPS_SIM == _ABIN32
1381 /* Now add space for saving the ra */
1382 offset
+= SIZEOF_VOID_P
;
1385 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1386 cfg
->stack_offset
= offset
;
1387 cfg
->arch
.local_alloc_offset
= cfg
->stack_offset
;
1392 mono_arch_create_vars (MonoCompile
*cfg
)
1394 MonoMethodSignature
*sig
;
1396 sig
= mono_method_signature (cfg
->method
);
1398 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1399 cfg
->vret_addr
= mono_compile_create_var (cfg
, &mono_defaults
.int_class
->byval_arg
, OP_ARG
);
1400 if (G_UNLIKELY (cfg
->verbose_level
> 1)) {
1401 printf ("vret_addr = ");
1402 mono_print_ins (cfg
->vret_addr
);
1407 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1408 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1412 * take the arguments and generate the arch-specific
1413 * instructions to properly call the function in call.
1414 * This includes pushing, moving arguments to the right register
1416 * Issue: who does the spilling if needed, and when?
1419 emit_sig_cookie (MonoCompile
*cfg
, MonoCallInst
*call
, CallInfo
*cinfo
)
1421 int sig_reg
= mono_alloc_ireg (cfg
);
1423 MONO_EMIT_NEW_ICONST (cfg
, sig_reg
, (guint32
)call
->signature
);
1424 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
,
1425 mips_sp
, cinfo
->sig_cookie
.offset
, sig_reg
);
1429 mono_arch_emit_call (MonoCompile
*cfg
, MonoCallInst
*call
)
1432 MonoMethodSignature
*sig
;
1437 sig
= call
->signature
;
1438 n
= sig
->param_count
+ sig
->hasthis
;
1440 cinfo
= calculate_sizes (sig
, sig
->pinvoke
);
1441 if (cinfo
->struct_ret
)
1442 call
->used_iregs
|= 1 << cinfo
->struct_ret
;
1444 for (i
= 0; i
< n
; ++i
) {
1445 ArgInfo
*ainfo
= cinfo
->args
+ i
;
1448 if (i
>= sig
->hasthis
)
1449 t
= sig
->params
[i
- sig
->hasthis
];
1451 t
= &mono_defaults
.int_class
->byval_arg
;
1452 t
= mini_type_get_underlying_type (cfg
->generic_sharing_context
, t
);
1454 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
))
1455 emit_sig_cookie (cfg
, call
, cinfo
);
1456 if (is_virtual
&& i
== 0) {
1457 /* the argument will be attached to the call instrucion */
1458 in
= call
->args
[i
];
1459 call
->used_iregs
|= 1 << ainfo
->reg
;
1462 in
= call
->args
[i
];
1463 if (ainfo
->regtype
== RegTypeGeneral
) {
1464 #if SIZEOF_REGISTER == 4
1465 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1466 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1467 ins
->dreg
= mono_alloc_ireg (cfg
);
1468 ins
->sreg1
= in
->dreg
+ 1;
1469 MONO_ADD_INS (cfg
->cbb
, ins
);
1470 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
+ 1, FALSE
);
1472 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1473 ins
->dreg
= mono_alloc_ireg (cfg
);
1474 ins
->sreg1
= in
->dreg
+ 2;
1475 MONO_ADD_INS (cfg
->cbb
, ins
);
1476 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1479 if (!t
->byref
&& (t
->type
== MONO_TYPE_R4
)) {
1482 #if PROMOTE_R4_TO_R8
1483 /* ??? - convert to single first? */
1484 MONO_INST_NEW (cfg
, ins
, OP_MIPS_CVTSD
);
1485 ins
->dreg
= mono_alloc_freg (cfg
);
1486 ins
->sreg1
= in
->dreg
;
1487 MONO_ADD_INS (cfg
->cbb
, ins
);
1492 /* trying to load float value into int registers */
1493 MONO_INST_NEW (cfg
, ins
, OP_MIPS_MFC1S
);
1494 ins
->dreg
= mono_alloc_ireg (cfg
);
1496 MONO_ADD_INS (cfg
->cbb
, ins
);
1497 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1498 } else if (!t
->byref
&& (t
->type
== MONO_TYPE_R8
)) {
1499 /* trying to load float value into int registers */
1500 MONO_INST_NEW (cfg
, ins
, OP_MIPS_MFC1D
);
1501 ins
->dreg
= mono_alloc_ireg (cfg
);
1502 ins
->sreg1
= in
->dreg
;
1503 MONO_ADD_INS (cfg
->cbb
, ins
);
1504 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1506 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1507 ins
->dreg
= mono_alloc_ireg (cfg
);
1508 ins
->sreg1
= in
->dreg
;
1509 MONO_ADD_INS (cfg
->cbb
, ins
);
1510 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1512 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
1513 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1514 ins
->opcode
= OP_OUTARG_VT
;
1515 ins
->sreg1
= in
->dreg
;
1516 ins
->klass
= in
->klass
;
1517 ins
->inst_p0
= call
;
1518 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1519 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1520 MONO_ADD_INS (cfg
->cbb
, ins
);
1521 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
1522 /* this is further handled in mono_arch_emit_outarg_vt () */
1523 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1524 ins
->opcode
= OP_OUTARG_VT
;
1525 ins
->sreg1
= in
->dreg
;
1526 ins
->klass
= in
->klass
;
1527 ins
->inst_p0
= call
;
1528 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1529 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1530 MONO_ADD_INS (cfg
->cbb
, ins
);
1531 } else if (ainfo
->regtype
== RegTypeBase
) {
1532 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1533 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1534 } else if (!t
->byref
&& ((t
->type
== MONO_TYPE_R4
) || (t
->type
== MONO_TYPE_R8
))) {
1535 if (t
->type
== MONO_TYPE_R8
)
1536 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER8_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1538 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER4_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1540 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1542 } else if (ainfo
->regtype
== RegTypeFP
) {
1543 if (t
->type
== MONO_TYPE_VALUETYPE
) {
1544 /* this is further handled in mono_arch_emit_outarg_vt () */
1545 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1546 ins
->opcode
= OP_OUTARG_VT
;
1547 ins
->sreg1
= in
->dreg
;
1548 ins
->klass
= in
->klass
;
1549 ins
->inst_p0
= call
;
1550 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1551 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1552 MONO_ADD_INS (cfg
->cbb
, ins
);
1554 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1556 int dreg
= mono_alloc_freg (cfg
);
1558 if (ainfo
->size
== 4) {
1559 MONO_EMIT_NEW_UNALU (cfg
, OP_MIPS_CVTSD
, dreg
, in
->dreg
);
1561 MONO_INST_NEW (cfg
, ins
, OP_FMOVE
);
1563 ins
->sreg1
= in
->dreg
;
1564 MONO_ADD_INS (cfg
->cbb
, ins
);
1567 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1568 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1571 g_assert_not_reached ();
1575 /* Emit the signature cookie in the case that there is no
1576 additional argument */
1577 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (n
== sig
->sentinelpos
))
1578 emit_sig_cookie (cfg
, call
, cinfo
);
1580 if (cinfo
->struct_ret
) {
1583 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
1584 vtarg
->sreg1
= call
->vret_var
->dreg
;
1585 vtarg
->dreg
= mono_alloc_preg (cfg
);
1586 MONO_ADD_INS (cfg
->cbb
, vtarg
);
1588 mono_call_inst_add_outarg_reg (cfg
, call
, vtarg
->dreg
, cinfo
->struct_ret
, FALSE
);
1592 * Reverse the call->out_args list.
1595 MonoInst
*prev
= NULL
, *list
= call
->out_args
, *next
;
1602 call
->out_args
= prev
;
1605 call
->stack_usage
= cinfo
->stack_usage
;
1606 cfg
->param_area
= MAX (cfg
->param_area
, cinfo
->stack_usage
);
1607 #if _MIPS_SIM == _ABIO32
1608 /* a0-a3 always present */
1609 cfg
->param_area
= MAX (cfg
->param_area
, 4 * SIZEOF_REGISTER
);
1611 cfg
->param_area
= (cfg
->param_area
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1612 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
1614 * should set more info in call, such as the stack space
1615 * used by the args that needs to be added back to esp
1622 mono_arch_emit_outarg_vt (MonoCompile
*cfg
, MonoInst
*ins
, MonoInst
*src
)
1624 MonoCallInst
*call
= (MonoCallInst
*)ins
->inst_p0
;
1625 ArgInfo
*ainfo
= ins
->inst_p1
;
1626 int ovf_size
= ainfo
->vtsize
;
1627 int doffset
= ainfo
->offset
;
1628 int i
, soffset
, dreg
;
1630 if (ainfo
->regtype
== RegTypeStructByVal
) {
1632 if (cfg
->verbose_level
> 0) {
1633 char* nm
= mono_method_full_name (cfg
->method
, TRUE
);
1634 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1635 nm
, doffset
, ainfo
->size
, ovf_size
);
1641 for (i
= 0; i
< ainfo
->size
; ++i
) {
1642 dreg
= mono_alloc_ireg (cfg
);
1643 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, dreg
, src
->dreg
, soffset
);
1644 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
+ i
, FALSE
);
1645 soffset
+= SIZEOF_REGISTER
;
1647 if (ovf_size
!= 0) {
1648 mini_emit_memcpy (cfg
, mips_fp
, doffset
, src
->dreg
, soffset
, ovf_size
* sizeof (gpointer
), 0);
1650 } else if (ainfo
->regtype
== RegTypeFP
) {
1651 int tmpr
= mono_alloc_freg (cfg
);
1653 if (ainfo
->size
== 4)
1654 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR4_MEMBASE
, tmpr
, src
->dreg
, 0);
1656 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR8_MEMBASE
, tmpr
, src
->dreg
, 0);
1657 dreg
= mono_alloc_freg (cfg
);
1658 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, dreg
, tmpr
);
1659 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1661 MonoInst
*vtcopy
= mono_compile_create_var (cfg
, &src
->klass
->byval_arg
, OP_LOCAL
);
1665 /* FIXME: alignment? */
1666 if (call
->signature
->pinvoke
) {
1667 size
= mono_type_native_stack_size (&src
->klass
->byval_arg
, NULL
);
1668 vtcopy
->backend
.is_pinvoke
= 1;
1670 size
= mini_type_stack_size (cfg
->generic_sharing_context
, &src
->klass
->byval_arg
, NULL
);
1673 g_assert (ovf_size
> 0);
1675 EMIT_NEW_VARLOADA (cfg
, load
, vtcopy
, vtcopy
->inst_vtype
);
1676 mini_emit_memcpy (cfg
, load
->dreg
, 0, src
->dreg
, 0, size
, 0);
1679 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_at
, ainfo
->offset
, load
->dreg
);
1681 mono_call_inst_add_outarg_reg (cfg
, call
, load
->dreg
, ainfo
->reg
, FALSE
);
1686 mono_arch_emit_setret (MonoCompile
*cfg
, MonoMethod
*method
, MonoInst
*val
)
1688 MonoType
*ret
= mini_type_get_underlying_type (cfg
->generic_sharing_context
,
1689 mono_method_signature (method
)->ret
);
1692 #if (SIZEOF_REGISTER == 4)
1693 if (ret
->type
== MONO_TYPE_I8
|| ret
->type
== MONO_TYPE_U8
) {
1696 MONO_INST_NEW (cfg
, ins
, OP_SETLRET
);
1697 ins
->sreg1
= val
->dreg
+ 1;
1698 ins
->sreg2
= val
->dreg
+ 2;
1699 MONO_ADD_INS (cfg
->cbb
, ins
);
1703 if (ret
->type
== MONO_TYPE_R8
) {
1704 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, cfg
->ret
->dreg
, val
->dreg
);
1707 if (ret
->type
== MONO_TYPE_R4
) {
1708 MONO_EMIT_NEW_UNALU (cfg
, OP_MIPS_CVTSD
, cfg
->ret
->dreg
, val
->dreg
);
1712 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, cfg
->ret
->dreg
, val
->dreg
);
1716 mono_arch_peephole_pass_1 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1718 MonoInst
*ins
, *n
, *last_ins
= NULL
;
1720 if (cfg
->verbose_level
> 2)
1721 g_print ("Basic block %d peephole pass 1\n", bb
->block_num
);
1724 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
1725 if (cfg
->verbose_level
> 2)
1726 mono_print_ins_index (0, ins
);
1728 switch (ins
->opcode
) {
1730 case OP_LOAD_MEMBASE
:
1731 case OP_LOADI4_MEMBASE
:
1733 * OP_IADD reg2, reg1, const1
1734 * OP_LOAD_MEMBASE const2(reg2), reg3
1736 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1738 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
)){
1739 int const1
= last_ins
->inst_imm
;
1740 int const2
= ins
->inst_offset
;
1742 if (mips_is_imm16 (const1
+ const2
)) {
1743 ins
->inst_basereg
= last_ins
->sreg1
;
1744 ins
->inst_offset
= const1
+ const2
;
1754 bb
->last_ins
= last_ins
;
1758 mono_arch_peephole_pass_2 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1760 MonoInst
*ins
, *n
, *last_ins
= NULL
;
1763 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
1764 MonoInst
*last_ins
= ins
->prev
;
1766 switch (ins
->opcode
) {
1768 /* remove unnecessary multiplication with 1 */
1769 if (ins
->inst_imm
== 1) {
1770 if (ins
->dreg
!= ins
->sreg1
) {
1771 ins
->opcode
= OP_MOVE
;
1773 MONO_DELETE_INS (bb
, ins
);
1777 int power2
= mono_is_power_of_two (ins
->inst_imm
);
1779 ins
->opcode
= OP_SHL_IMM
;
1780 ins
->inst_imm
= power2
;
1784 case OP_LOAD_MEMBASE
:
1785 case OP_LOADI4_MEMBASE
:
1787 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1788 * OP_LOAD_MEMBASE offset(basereg), reg
1790 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_REG
1791 || last_ins
->opcode
== OP_STORE_MEMBASE_REG
) &&
1792 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1793 ins
->inst_offset
== last_ins
->inst_offset
) {
1794 if (ins
->dreg
== last_ins
->sreg1
) {
1795 MONO_DELETE_INS (bb
, ins
);
1798 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1799 ins
->opcode
= OP_MOVE
;
1800 ins
->sreg1
= last_ins
->sreg1
;
1805 * Note: reg1 must be different from the basereg in the second load
1806 * OP_LOAD_MEMBASE offset(basereg), reg1
1807 * OP_LOAD_MEMBASE offset(basereg), reg2
1809 * OP_LOAD_MEMBASE offset(basereg), reg1
1810 * OP_MOVE reg1, reg2
1812 if (last_ins
&& (last_ins
->opcode
== OP_LOADI4_MEMBASE
1813 || last_ins
->opcode
== OP_LOAD_MEMBASE
) &&
1814 ins
->inst_basereg
!= last_ins
->dreg
&&
1815 ins
->inst_basereg
== last_ins
->inst_basereg
&&
1816 ins
->inst_offset
== last_ins
->inst_offset
) {
1818 if (ins
->dreg
== last_ins
->dreg
) {
1819 MONO_DELETE_INS (bb
, ins
);
1822 ins
->opcode
= OP_MOVE
;
1823 ins
->sreg1
= last_ins
->dreg
;
1826 //g_assert_not_reached ();
1831 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1832 * OP_LOAD_MEMBASE offset(basereg), reg
1834 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1835 * OP_ICONST reg, imm
1837 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_IMM
1838 || last_ins
->opcode
== OP_STORE_MEMBASE_IMM
) &&
1839 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1840 ins
->inst_offset
== last_ins
->inst_offset
) {
1841 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1842 ins
->opcode
= OP_ICONST
;
1843 ins
->inst_c0
= last_ins
->inst_imm
;
1844 g_assert_not_reached (); // check this rule
1849 case OP_LOADU1_MEMBASE
:
1850 case OP_LOADI1_MEMBASE
:
1851 if (last_ins
&& (last_ins
->opcode
== OP_STOREI1_MEMBASE_REG
) &&
1852 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1853 ins
->inst_offset
== last_ins
->inst_offset
) {
1854 ins
->opcode
= (ins
->opcode
== OP_LOADI1_MEMBASE
) ? OP_ICONV_TO_I1
: OP_ICONV_TO_U1
;
1855 ins
->sreg1
= last_ins
->sreg1
;
1858 case OP_LOADU2_MEMBASE
:
1859 case OP_LOADI2_MEMBASE
:
1860 if (last_ins
&& (last_ins
->opcode
== OP_STOREI2_MEMBASE_REG
) &&
1861 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1862 ins
->inst_offset
== last_ins
->inst_offset
) {
1863 ins
->opcode
= (ins
->opcode
== OP_LOADI2_MEMBASE
) ? OP_ICONV_TO_I2
: OP_ICONV_TO_U2
;
1864 ins
->sreg1
= last_ins
->sreg1
;
1867 case OP_ICONV_TO_I4
:
1868 case OP_ICONV_TO_U4
:
1870 ins
->opcode
= OP_MOVE
;
1874 if (ins
->dreg
== ins
->sreg1
) {
1875 MONO_DELETE_INS (bb
, ins
);
1879 * OP_MOVE sreg, dreg
1880 * OP_MOVE dreg, sreg
1882 if (last_ins
&& last_ins
->opcode
== OP_MOVE
&&
1883 ins
->sreg1
== last_ins
->dreg
&&
1884 ins
->dreg
== last_ins
->sreg1
) {
1885 MONO_DELETE_INS (bb
, ins
);
1893 bb
->last_ins
= last_ins
;
1897 mono_arch_decompose_long_opts (MonoCompile
*cfg
, MonoInst
*ins
)
1905 switch (ins
->opcode
) {
1908 case OP_LCOMPARE_IMM
:
1909 mono_print_ins (ins
);
1910 g_assert_not_reached ();
1913 tmp1
= mono_alloc_ireg (cfg
);
1914 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
1915 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
1916 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
1917 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
1918 ins
->opcode
= OP_NOP
;
1922 tmp1
= mono_alloc_ireg (cfg
);
1923 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, ins
->dreg
+1, ins
->sreg1
+1, ins
->inst_ls_word
);
1924 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
1925 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, ins
->dreg
+2, ins
->sreg1
+2, ins
->inst_ms_word
);
1926 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
1927 ins
->opcode
= OP_NOP
;
1931 tmp1
= mono_alloc_ireg (cfg
);
1932 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
1933 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
1934 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
1935 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
1936 ins
->opcode
= OP_NOP
;
1940 tmp1
= mono_alloc_ireg (cfg
);
1941 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, ins
->dreg
+1, ins
->sreg1
+1, ins
->inst_ls_word
);
1942 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
1943 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, ins
->dreg
+2, ins
->sreg1
+2, ins
->inst_ms_word
);
1944 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
1945 ins
->opcode
= OP_NOP
;
1956 mono_print_ins (ins
);
1957 g_assert_not_reached ();
1960 tmp1
= mono_alloc_ireg (cfg
);
1961 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, mips_zero
, ins
->sreg1
+1);
1962 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, mips_zero
, ins
->dreg
+1);
1963 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, mips_zero
, ins
->sreg1
+2);
1964 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
1965 ins
->opcode
= OP_NOP
;
1972 case OP_LCONV_TO_I1
:
1973 case OP_LCONV_TO_I2
:
1974 case OP_LCONV_TO_I4
:
1975 case OP_LCONV_TO_I8
:
1976 case OP_LCONV_TO_R4
:
1977 case OP_LCONV_TO_R8
:
1978 case OP_LCONV_TO_U4
:
1979 case OP_LCONV_TO_U8
:
1980 case OP_LCONV_TO_U2
:
1981 case OP_LCONV_TO_U1
:
1983 case OP_LCONV_TO_OVF_I
:
1984 case OP_LCONV_TO_OVF_U
:
1986 mono_print_ins (ins
);
1987 g_assert_not_reached ();
1990 tmp1
= mono_alloc_ireg (cfg
);
1991 tmp2
= mono_alloc_ireg (cfg
);
1992 tmp3
= mono_alloc_ireg (cfg
);
1993 tmp4
= mono_alloc_ireg (cfg
);
1994 tmp5
= mono_alloc_ireg (cfg
);
1996 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
1998 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
1999 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp5
, ins
->dreg
+1, ins
->sreg1
+1);
2001 /* add the high 32-bits, and add in the carry from the low 32-bits */
2002 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2003 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, tmp5
, ins
->dreg
+2);
2005 /* Overflow happens if
2006 * neg + neg = pos or
2008 * XOR of the high bits returns 0 if the signs match
2009 * XOR of that with the high bit of the result return 1 if overflow.
2012 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2013 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
+2, ins
->sreg2
+2);
2015 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2016 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->dreg
+2, ins
->sreg2
+2);
2017 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tmp2
, tmp2
);
2019 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2020 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tmp3
, tmp2
, tmp1
);
2021 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp4
, tmp3
, 31);
2023 /* Now, if (tmp4 == 0) then overflow */
2024 MONO_EMIT_NEW_COMPARE_EXC (cfg
, EQ
, tmp4
, mips_zero
, "OverflowException");
2025 ins
->opcode
= OP_NOP
;
2028 case OP_LADD_OVF_UN
:
2029 tmp1
= mono_alloc_ireg (cfg
);
2030 tmp2
= mono_alloc_ireg (cfg
);
2032 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2033 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
2034 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2035 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, tmp1
, ins
->dreg
+2);
2036 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp2
, ins
->dreg
+2, ins
->sreg1
+2);
2037 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp2
, mips_zero
, "OverflowException");
2038 ins
->opcode
= OP_NOP
;
2042 case OP_LMUL_OVF_UN
:
2043 mono_print_ins (ins
);
2044 g_assert_not_reached ();
2047 tmp1
= mono_alloc_ireg (cfg
);
2048 tmp2
= mono_alloc_ireg (cfg
);
2049 tmp3
= mono_alloc_ireg (cfg
);
2050 tmp4
= mono_alloc_ireg (cfg
);
2051 tmp5
= mono_alloc_ireg (cfg
);
2053 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2055 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp5
, ins
->sreg1
+1, ins
->dreg
+1);
2056 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2057 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp5
);
2059 /* Overflow happens if
2060 * neg - pos = pos or
2062 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2064 * tmp1 = (lhs ^ rhs)
2065 * tmp2 = (lhs ^ result)
2066 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2069 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
+2, ins
->sreg2
+2);
2070 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->sreg1
+2, ins
->dreg
+2);
2071 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tmp3
, tmp2
, tmp1
);
2072 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp4
, tmp3
, 31);
2074 /* Now, if (tmp4 == 1) then overflow */
2075 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp4
, mips_zero
, "OverflowException");
2076 ins
->opcode
= OP_NOP
;
2079 case OP_LSUB_OVF_UN
:
2080 tmp1
= mono_alloc_ireg (cfg
);
2081 tmp2
= mono_alloc_ireg (cfg
);
2083 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2084 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
2085 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2086 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2088 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp2
, ins
->sreg1
+2, ins
->dreg
+2);
2089 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp2
, mips_zero
, "OverflowException");
2090 ins
->opcode
= OP_NOP
;
2093 case OP_LCONV_TO_OVF_I1_UN
:
2094 case OP_LCONV_TO_OVF_I2_UN
:
2095 case OP_LCONV_TO_OVF_I4_UN
:
2096 case OP_LCONV_TO_OVF_I8_UN
:
2097 case OP_LCONV_TO_OVF_U1_UN
:
2098 case OP_LCONV_TO_OVF_U2_UN
:
2099 case OP_LCONV_TO_OVF_U4_UN
:
2100 case OP_LCONV_TO_OVF_U8_UN
:
2101 case OP_LCONV_TO_OVF_I_UN
:
2102 case OP_LCONV_TO_OVF_U_UN
:
2103 case OP_LCONV_TO_OVF_I1
:
2104 case OP_LCONV_TO_OVF_U1
:
2105 case OP_LCONV_TO_OVF_I2
:
2106 case OP_LCONV_TO_OVF_U2
:
2107 case OP_LCONV_TO_OVF_I4
:
2108 case OP_LCONV_TO_OVF_U4
:
2109 case OP_LCONV_TO_OVF_I8
:
2110 case OP_LCONV_TO_OVF_U8
:
2118 case OP_LCONV_TO_R_UN
:
2124 case OP_LSHR_UN_IMM
:
2126 case OP_LDIV_UN_IMM
:
2128 case OP_LREM_UN_IMM
:
2139 mono_print_ins (ins
);
2140 g_assert_not_reached ();
2142 case OP_LCONV_TO_R8_2
:
2143 case OP_LCONV_TO_R4_2
:
2144 case OP_LCONV_TO_R_UN_2
:
2146 case OP_LCONV_TO_OVF_I4_2
:
2147 tmp1
= mono_alloc_ireg (cfg
);
2149 /* Overflows if reg2 != sign extension of reg1 */
2150 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp1
, ins
->sreg1
, 31);
2151 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, ins
->sreg2
, tmp1
, "OverflowException");
2152 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
2153 ins
->opcode
= OP_NOP
;
2160 mono_print_ins (ins
);
2161 g_assert_not_reached ();
2169 mono_arch_decompose_opts (MonoCompile
*cfg
, MonoInst
*ins
)
2177 switch (ins
->opcode
) {
2179 tmp1
= mono_alloc_ireg (cfg
);
2180 tmp2
= mono_alloc_ireg (cfg
);
2181 tmp3
= mono_alloc_ireg (cfg
);
2182 tmp4
= mono_alloc_ireg (cfg
);
2183 tmp5
= mono_alloc_ireg (cfg
);
2185 /* add the operands */
2187 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2189 /* Overflow happens if
2190 * neg + neg = pos or
2193 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2194 * XOR of the high bit returns 0 if the signs match
2195 * XOR of that with the high bit of the result return 1 if overflow.
2198 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2199 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
, ins
->sreg2
);
2201 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2202 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->dreg
, ins
->sreg2
);
2203 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tmp3
, tmp2
);
2205 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2206 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tmp4
, tmp3
, tmp1
);
2208 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp5
, tmp4
, 31);
2210 /* Now, if (tmp4 == 0) then overflow */
2211 MONO_EMIT_NEW_COMPARE_EXC (cfg
, EQ
, tmp5
, mips_zero
, "OverflowException");
2212 ins
->opcode
= OP_NOP
;
2215 case OP_IADD_OVF_UN
:
2216 tmp1
= mono_alloc_ireg (cfg
);
2218 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2219 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
, ins
->sreg1
);
2220 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp1
, mips_zero
, "OverflowException");
2221 ins
->opcode
= OP_NOP
;
2225 tmp1
= mono_alloc_ireg (cfg
);
2226 tmp2
= mono_alloc_ireg (cfg
);
2227 tmp3
= mono_alloc_ireg (cfg
);
2228 tmp4
= mono_alloc_ireg (cfg
);
2229 tmp5
= mono_alloc_ireg (cfg
);
2231 /* add the operands */
2233 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2235 /* Overflow happens if
2236 * neg - pos = pos or
2238 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2240 * tmp1 = (lhs ^ rhs)
2241 * tmp2 = (lhs ^ result)
2242 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2245 /* tmp3 = 1 if the signs of the two inputs differ */
2246 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
, ins
->sreg2
);
2247 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->sreg1
, ins
->dreg
);
2248 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_MIPS_SLTI
, tmp3
, tmp1
, 0);
2249 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_MIPS_SLTI
, tmp4
, tmp2
, 0);
2250 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tmp5
, tmp4
, tmp3
);
2252 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp5
, mips_zero
, "OverflowException");
2253 ins
->opcode
= OP_NOP
;
2256 case OP_ISUB_OVF_UN
:
2257 tmp1
= mono_alloc_ireg (cfg
);
2259 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2260 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
, ins
->dreg
);
2261 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp1
, mips_zero
, "OverflowException");
2262 ins
->opcode
= OP_NOP
;
2269 map_to_reg_reg_op (int op
)
2278 case OP_COMPARE_IMM
:
2280 case OP_ICOMPARE_IMM
:
2282 case OP_LCOMPARE_IMM
:
2298 case OP_LOAD_MEMBASE
:
2299 return OP_LOAD_MEMINDEX
;
2300 case OP_LOADI4_MEMBASE
:
2301 return OP_LOADI4_MEMINDEX
;
2302 case OP_LOADU4_MEMBASE
:
2303 return OP_LOADU4_MEMINDEX
;
2304 case OP_LOADU1_MEMBASE
:
2305 return OP_LOADU1_MEMINDEX
;
2306 case OP_LOADI2_MEMBASE
:
2307 return OP_LOADI2_MEMINDEX
;
2308 case OP_LOADU2_MEMBASE
:
2309 return OP_LOADU2_MEMINDEX
;
2310 case OP_LOADI1_MEMBASE
:
2311 return OP_LOADI1_MEMINDEX
;
2312 case OP_LOADR4_MEMBASE
:
2313 return OP_LOADR4_MEMINDEX
;
2314 case OP_LOADR8_MEMBASE
:
2315 return OP_LOADR8_MEMINDEX
;
2316 case OP_STOREI1_MEMBASE_REG
:
2317 return OP_STOREI1_MEMINDEX
;
2318 case OP_STOREI2_MEMBASE_REG
:
2319 return OP_STOREI2_MEMINDEX
;
2320 case OP_STOREI4_MEMBASE_REG
:
2321 return OP_STOREI4_MEMINDEX
;
2322 case OP_STORE_MEMBASE_REG
:
2323 return OP_STORE_MEMINDEX
;
2324 case OP_STORER4_MEMBASE_REG
:
2325 return OP_STORER4_MEMINDEX
;
2326 case OP_STORER8_MEMBASE_REG
:
2327 return OP_STORER8_MEMINDEX
;
2328 case OP_STORE_MEMBASE_IMM
:
2329 return OP_STORE_MEMBASE_REG
;
2330 case OP_STOREI1_MEMBASE_IMM
:
2331 return OP_STOREI1_MEMBASE_REG
;
2332 case OP_STOREI2_MEMBASE_IMM
:
2333 return OP_STOREI2_MEMBASE_REG
;
2334 case OP_STOREI4_MEMBASE_IMM
:
2335 return OP_STOREI4_MEMBASE_REG
;
2336 case OP_STOREI8_MEMBASE_IMM
:
2337 return OP_STOREI8_MEMBASE_REG
;
2339 return mono_op_imm_to_op (op
);
2343 map_to_mips_op (int op
)
2347 return OP_MIPS_FBEQ
;
2349 return OP_MIPS_FBGE
;
2351 return OP_MIPS_FBGT
;
2353 return OP_MIPS_FBLE
;
2355 return OP_MIPS_FBLT
;
2357 return OP_MIPS_FBNE
;
2359 return OP_MIPS_FBGE_UN
;
2361 return OP_MIPS_FBGT_UN
;
2363 return OP_MIPS_FBLE_UN
;
2365 return OP_MIPS_FBLT_UN
;
2373 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op
), __FUNCTION__
);
2374 g_assert_not_reached ();
2378 #define NEW_INS(cfg,after,dest,op) do { \
2379 MONO_INST_NEW((cfg), (dest), (op)); \
2380 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2383 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2385 MONO_INST_NEW(cfg, temp, (op)); \
2386 mono_bblock_insert_after_ins (bb, (pos), temp); \
2387 temp->dreg = (_dreg); \
2388 temp->sreg1 = (_sreg1); \
2389 temp->sreg2 = (_sreg2); \
2393 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2395 MONO_INST_NEW(cfg, temp, (op)); \
2396 mono_bblock_insert_after_ins (bb, (pos), temp); \
2397 temp->dreg = (_dreg); \
2398 temp->sreg1 = (_sreg1); \
2399 temp->inst_c0 = (_imm); \
2404 * Remove from the instruction list the instructions that can't be
2405 * represented with very simple instructions with no register
2409 mono_arch_lowering_pass (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2411 MonoInst
*ins
, *next
, *temp
, *last_ins
= NULL
;
2415 if (cfg
->verbose_level
> 2) {
2418 g_print ("BASIC BLOCK %d (before lowering)\n", bb
->block_num
);
2419 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2420 mono_print_ins_index (idx
++, ins
);
2426 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2428 switch (ins
->opcode
) {
2433 /* Branch opts can eliminate the branch */
2434 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2435 ins
->opcode
= OP_NOP
;
2440 case OP_COMPARE_IMM
:
2441 case OP_ICOMPARE_IMM
:
2442 case OP_LCOMPARE_IMM
:
2444 /* Branch opts can eliminate the branch */
2445 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2446 ins
->opcode
= OP_NOP
;
2449 if (ins
->inst_imm
) {
2450 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2451 temp
->inst_c0
= ins
->inst_imm
;
2452 temp
->dreg
= mono_alloc_ireg (cfg
);
2453 ins
->sreg2
= temp
->dreg
;
2457 ins
->sreg2
= mips_zero
;
2459 if (ins
->opcode
== OP_COMPARE_IMM
)
2460 ins
->opcode
= OP_COMPARE
;
2461 else if (ins
->opcode
== OP_ICOMPARE_IMM
)
2462 ins
->opcode
= OP_ICOMPARE
;
2463 else if (ins
->opcode
== OP_LCOMPARE_IMM
)
2464 ins
->opcode
= OP_LCOMPARE
;
2467 case OP_IDIV_UN_IMM
:
2470 case OP_IREM_UN_IMM
:
2471 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2472 temp
->inst_c0
= ins
->inst_imm
;
2473 temp
->dreg
= mono_alloc_ireg (cfg
);
2474 ins
->sreg2
= temp
->dreg
;
2475 if (ins
->opcode
== OP_IDIV_IMM
)
2476 ins
->opcode
= OP_IDIV
;
2477 else if (ins
->opcode
== OP_IREM_IMM
)
2478 ins
->opcode
= OP_IREM
;
2479 else if (ins
->opcode
== OP_IDIV_UN_IMM
)
2480 ins
->opcode
= OP_IDIV_UN
;
2481 else if (ins
->opcode
== OP_IREM_UN_IMM
)
2482 ins
->opcode
= OP_IREM_UN
;
2484 /* handle rem separately */
2491 if ((ins
->inst_imm
& 0xffff0000) && (ins
->inst_imm
& 0xffff)) {
2492 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2493 temp
->inst_c0
= ins
->inst_imm
;
2494 temp
->dreg
= mono_alloc_ireg (cfg
);
2495 ins
->sreg2
= temp
->dreg
;
2496 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2506 /* unsigned 16 bit immediate */
2507 if (ins
->inst_imm
& 0xffff0000) {
2508 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2509 temp
->inst_c0
= ins
->inst_imm
;
2510 temp
->dreg
= mono_alloc_ireg (cfg
);
2511 ins
->sreg2
= temp
->dreg
;
2512 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2519 /* signed 16 bit immediate */
2520 if (!mips_is_imm16 (ins
->inst_imm
)) {
2521 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2522 temp
->inst_c0
= ins
->inst_imm
;
2523 temp
->dreg
= mono_alloc_ireg (cfg
);
2524 ins
->sreg2
= temp
->dreg
;
2525 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2531 if (!mips_is_imm16 (-ins
->inst_imm
)) {
2532 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2533 temp
->inst_c0
= ins
->inst_imm
;
2534 temp
->dreg
= mono_alloc_ireg (cfg
);
2535 ins
->sreg2
= temp
->dreg
;
2536 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2542 if (ins
->inst_imm
== 1) {
2543 ins
->opcode
= OP_MOVE
;
2546 if (ins
->inst_imm
== 0) {
2547 ins
->opcode
= OP_ICONST
;
2551 imm
= mono_is_power_of_two (ins
->inst_imm
);
2553 ins
->opcode
= OP_SHL_IMM
;
2554 ins
->inst_imm
= imm
;
2557 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2558 temp
->inst_c0
= ins
->inst_imm
;
2559 temp
->dreg
= mono_alloc_ireg (cfg
);
2560 ins
->sreg2
= temp
->dreg
;
2561 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2564 case OP_LOCALLOC_IMM
:
2565 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2566 temp
->inst_c0
= ins
->inst_imm
;
2567 temp
->dreg
= mono_alloc_ireg (cfg
);
2568 ins
->sreg1
= temp
->dreg
;
2569 ins
->opcode
= OP_LOCALLOC
;
2572 case OP_LOAD_MEMBASE
:
2573 case OP_LOADI4_MEMBASE
:
2574 case OP_LOADU4_MEMBASE
:
2575 case OP_LOADI2_MEMBASE
:
2576 case OP_LOADU2_MEMBASE
:
2577 case OP_LOADI1_MEMBASE
:
2578 case OP_LOADU1_MEMBASE
:
2579 case OP_LOADR4_MEMBASE
:
2580 case OP_LOADR8_MEMBASE
:
2581 case OP_STORE_MEMBASE_REG
:
2582 case OP_STOREI4_MEMBASE_REG
:
2583 case OP_STOREI2_MEMBASE_REG
:
2584 case OP_STOREI1_MEMBASE_REG
:
2585 case OP_STORER4_MEMBASE_REG
:
2586 case OP_STORER8_MEMBASE_REG
:
2587 /* we can do two things: load the immed in a register
2588 * and use an indexed load, or see if the immed can be
2589 * represented as an ad_imm + a load with a smaller offset
2590 * that fits. We just do the first for now, optimize later.
2592 if (mips_is_imm16 (ins
->inst_offset
))
2594 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2595 temp
->inst_c0
= ins
->inst_offset
;
2596 temp
->dreg
= mono_alloc_ireg (cfg
);
2597 ins
->sreg2
= temp
->dreg
;
2598 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2601 case OP_STORE_MEMBASE_IMM
:
2602 case OP_STOREI1_MEMBASE_IMM
:
2603 case OP_STOREI2_MEMBASE_IMM
:
2604 case OP_STOREI4_MEMBASE_IMM
:
2605 case OP_STOREI8_MEMBASE_IMM
:
2606 if (!ins
->inst_imm
) {
2607 ins
->sreg1
= mips_zero
;
2608 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2611 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2612 temp
->inst_c0
= ins
->inst_imm
;
2613 temp
->dreg
= mono_alloc_ireg (cfg
);
2614 ins
->sreg1
= temp
->dreg
;
2615 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2617 goto loop_start
; /* make it handle the possibly big ins->inst_offset */
2623 /* Branch opts can eliminate the branch */
2624 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2625 ins
->opcode
= OP_NOP
;
2631 * remap compare/branch and compare/set
2632 * to MIPS specific opcodes.
2634 ins
->opcode
= OP_NOP
;
2635 next
->opcode
= map_to_mips_op (next
->opcode
);
2636 next
->sreg1
= ins
->sreg1
;
2637 next
->sreg2
= ins
->sreg2
;
2643 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2644 temp
->inst_c0
= (guint32
)ins
->inst_p0
;
2645 temp
->dreg
= mono_alloc_ireg (cfg
);
2646 ins
->inst_basereg
= temp
->dreg
;
2647 ins
->inst_offset
= 0;
2648 ins
->opcode
= ins
->opcode
== OP_R4CONST
? OP_LOADR4_MEMBASE
: OP_LOADR8_MEMBASE
;
2650 /* make it handle the possibly big ins->inst_offset
2651 * later optimize to use lis + load_membase
2656 g_assert (ins_is_compare(last_ins
));
2657 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->sreg1
, last_ins
->sreg2
);
2658 last_ins
->opcode
= OP_NOP
;
2662 g_assert (ins_is_compare(last_ins
));
2663 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->sreg1
, last_ins
->sreg2
);
2664 last_ins
->opcode
= OP_NOP
;
2668 g_assert (ins_is_compare(last_ins
));
2669 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2670 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2671 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2675 g_assert (ins_is_compare(last_ins
));
2676 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2677 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2678 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2682 g_assert (ins_is_compare(last_ins
));
2683 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2684 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2685 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2689 g_assert (ins_is_compare(last_ins
));
2690 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2691 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2692 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2696 g_assert (ins_is_compare(last_ins
));
2697 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2698 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2699 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2703 g_assert (ins_is_compare(last_ins
));
2704 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2705 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2706 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2710 g_assert (ins_is_compare(last_ins
));
2711 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2712 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2713 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2717 g_assert (ins_is_compare(last_ins
));
2718 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2719 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2720 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2725 g_assert (ins_is_compare(last_ins
));
2726 last_ins
->opcode
= OP_IXOR
;
2727 last_ins
->dreg
= mono_alloc_ireg(cfg
);
2728 INS_REWRITE_IMM(ins
, OP_MIPS_SLTIU
, last_ins
->dreg
, 1);
2733 INS_REWRITE(ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2734 last_ins
->opcode
= OP_NOP
;
2740 INS_REWRITE(ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2741 last_ins
->opcode
= OP_NOP
;
2746 g_assert (ins_is_compare(last_ins
));
2747 INS_REWRITE(ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2748 MONO_DELETE_INS(bb
, last_ins
);
2753 g_assert (ins_is_compare(last_ins
));
2754 INS_REWRITE(ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2755 MONO_DELETE_INS(bb
, last_ins
);
2758 case OP_COND_EXC_EQ
:
2759 case OP_COND_EXC_IEQ
:
2760 g_assert (ins_is_compare(last_ins
));
2761 INS_REWRITE(ins
, OP_MIPS_COND_EXC_EQ
, last_ins
->sreg1
, last_ins
->sreg2
);
2762 MONO_DELETE_INS(bb
, last_ins
);
2765 case OP_COND_EXC_GE
:
2766 case OP_COND_EXC_IGE
:
2767 g_assert (ins_is_compare(last_ins
));
2768 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GE
, last_ins
->sreg1
, last_ins
->sreg2
);
2769 MONO_DELETE_INS(bb
, last_ins
);
2772 case OP_COND_EXC_GT
:
2773 case OP_COND_EXC_IGT
:
2774 g_assert (ins_is_compare(last_ins
));
2775 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GT
, last_ins
->sreg1
, last_ins
->sreg2
);
2776 MONO_DELETE_INS(bb
, last_ins
);
2779 case OP_COND_EXC_LE
:
2780 case OP_COND_EXC_ILE
:
2781 g_assert (ins_is_compare(last_ins
));
2782 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LE
, last_ins
->sreg1
, last_ins
->sreg2
);
2783 MONO_DELETE_INS(bb
, last_ins
);
2786 case OP_COND_EXC_LT
:
2787 case OP_COND_EXC_ILT
:
2788 g_assert (ins_is_compare(last_ins
));
2789 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LT
, last_ins
->sreg1
, last_ins
->sreg2
);
2790 MONO_DELETE_INS(bb
, last_ins
);
2793 case OP_COND_EXC_NE_UN
:
2794 case OP_COND_EXC_INE_UN
:
2795 g_assert (ins_is_compare(last_ins
));
2796 INS_REWRITE(ins
, OP_MIPS_COND_EXC_NE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2797 MONO_DELETE_INS(bb
, last_ins
);
2800 case OP_COND_EXC_GE_UN
:
2801 case OP_COND_EXC_IGE_UN
:
2802 g_assert (ins_is_compare(last_ins
));
2803 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2804 MONO_DELETE_INS(bb
, last_ins
);
2807 case OP_COND_EXC_GT_UN
:
2808 case OP_COND_EXC_IGT_UN
:
2809 g_assert (ins_is_compare(last_ins
));
2810 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GT_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2811 MONO_DELETE_INS(bb
, last_ins
);
2814 case OP_COND_EXC_LE_UN
:
2815 case OP_COND_EXC_ILE_UN
:
2816 g_assert (ins_is_compare(last_ins
));
2817 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2818 MONO_DELETE_INS(bb
, last_ins
);
2821 case OP_COND_EXC_LT_UN
:
2822 case OP_COND_EXC_ILT_UN
:
2823 g_assert (ins_is_compare(last_ins
));
2824 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LT_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2825 MONO_DELETE_INS(bb
, last_ins
);
2828 case OP_COND_EXC_OV
:
2829 case OP_COND_EXC_IOV
: {
2830 int tmp1
, tmp2
, tmp3
, tmp4
, tmp5
;
2831 MonoInst
*pos
= last_ins
;
2833 /* Overflow happens if
2834 * neg + neg = pos or
2837 * (bit31s of operands match) AND (bit31 of operand
2838 * != bit31 of result)
2839 * XOR of the high bit returns 0 if the signs match
2840 * XOR of that with the high bit of the result return 1
2843 g_assert (last_ins
->opcode
== OP_IADC
);
2845 tmp1
= mono_alloc_ireg (cfg
);
2846 tmp2
= mono_alloc_ireg (cfg
);
2847 tmp3
= mono_alloc_ireg (cfg
);
2848 tmp4
= mono_alloc_ireg (cfg
);
2849 tmp5
= mono_alloc_ireg (cfg
);
2851 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2852 INS (pos
, OP_IXOR
, tmp1
, last_ins
->sreg1
, last_ins
->sreg2
);
2854 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2855 INS (pos
, OP_IXOR
, tmp2
, last_ins
->dreg
, last_ins
->sreg2
);
2856 INS (pos
, OP_INOT
, tmp3
, tmp2
, -1);
2858 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2859 INS (pos
, OP_IOR
, tmp4
, tmp3
, tmp1
);
2860 INS_IMM (pos
, OP_SHR_IMM
, tmp5
, tmp4
, 31);
2862 /* Now, if (tmp5 == 0) then overflow */
2863 INS_REWRITE(ins
, OP_MIPS_COND_EXC_EQ
, tmp5
, mips_zero
);
2868 case OP_COND_EXC_NO
:
2869 case OP_COND_EXC_INO
:
2870 g_assert_not_reached ();
2874 case OP_COND_EXC_IC
:
2875 g_assert_not_reached ();
2878 case OP_COND_EXC_NC
:
2879 case OP_COND_EXC_INC
:
2880 g_assert_not_reached ();
2886 bb
->last_ins
= last_ins
;
2887 bb
->max_vreg
= cfg
->next_vreg
;
2890 if (cfg
->verbose_level
> 2) {
2893 g_print ("BASIC BLOCK %d (after lowering)\n", bb
->block_num
);
2894 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2895 mono_print_ins_index (idx
++, ins
);
2904 emit_float_to_int (MonoCompile
*cfg
, guchar
*code
, int dreg
, int sreg
, int size
, gboolean is_signed
)
2906 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
2908 mips_truncwd (code
, mips_ftemp
, sreg
);
2910 mips_cvtwd (code
, mips_ftemp
, sreg
);
2912 mips_mfc1 (code
, dreg
, mips_ftemp
);
2915 mips_andi (code
, dreg
, dreg
, 0xff);
2916 else if (size
== 2) {
2917 mips_sll (code
, dreg
, dreg
, 16);
2918 mips_srl (code
, dreg
, dreg
, 16);
2922 mips_sll (code
, dreg
, dreg
, 24);
2923 mips_sra (code
, dreg
, dreg
, 24);
2925 else if (size
== 2) {
2926 mips_sll (code
, dreg
, dreg
, 16);
2927 mips_sra (code
, dreg
, dreg
, 16);
2934 * emit_load_volatile_arguments:
2936 * Load volatile arguments from the stack to the original input registers.
2937 * Required before a tail call.
2940 emit_load_volatile_arguments(MonoCompile
*cfg
, guint8
*code
)
2942 MonoMethod
*method
= cfg
->method
;
2943 MonoMethodSignature
*sig
;
2948 sig
= mono_method_signature (method
);
2949 cinfo
= calculate_sizes (sig
, sig
->pinvoke
);
2950 if (cinfo
->struct_ret
) {
2951 ArgInfo
*ainfo
= &cinfo
->ret
;
2952 inst
= cfg
->vret_addr
;
2953 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
2956 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
2957 ArgInfo
*ainfo
= cinfo
->args
+ i
;
2958 inst
= cfg
->args
[i
];
2959 if (inst
->opcode
== OP_REGVAR
) {
2960 if (ainfo
->regtype
== RegTypeGeneral
)
2961 MIPS_MOVE (code
, ainfo
->reg
, inst
->dreg
);
2962 else if (ainfo
->regtype
== RegTypeFP
)
2963 g_assert_not_reached();
2964 else if (ainfo
->regtype
== RegTypeBase
) {
2967 g_assert_not_reached ();
2969 if (ainfo
->regtype
== RegTypeGeneral
) {
2970 g_assert (mips_is_imm16 (inst
->inst_offset
));
2971 switch (ainfo
->size
) {
2973 mips_lb (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
2976 mips_lh (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
2980 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
2983 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
2984 mips_lw (code
, ainfo
->reg
+ 1, inst
->inst_basereg
, inst
->inst_offset
+ 4);
2987 g_assert_not_reached ();
2990 } else if (ainfo
->regtype
== RegTypeBase
) {
2992 } else if (ainfo
->regtype
== RegTypeFP
) {
2993 g_assert (mips_is_imm16 (inst
->inst_offset
));
2994 if (ainfo
->size
== 8) {
2995 #if _MIPS_SIM == _ABIO32
2996 mips_lwc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+4);
2997 mips_lwc1 (code
, ainfo
->reg
+1, inst
->inst_basereg
, inst
->inst_offset
);
2998 #elif _MIPS_SIM == _ABIN32
2999 mips_ldc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3002 else if (ainfo
->size
== 4)
3003 mips_lwc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3005 g_assert_not_reached ();
3006 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
3008 int doffset
= inst
->inst_offset
;
3010 g_assert (mips_is_imm16 (inst
->inst_offset
));
3011 g_assert (mips_is_imm16 (inst
->inst_offset
+ ainfo
->size
* sizeof (gpointer
)));
3012 for (i
= 0; i
< ainfo
->size
; ++i
) {
3013 mips_lw (code
, ainfo
->reg
+ i
, inst
->inst_basereg
, doffset
);
3014 doffset
+= SIZEOF_REGISTER
;
3016 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
3017 g_assert (mips_is_imm16 (inst
->inst_offset
));
3018 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3020 g_assert_not_reached ();
3030 emit_reserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3032 int size
= cfg
->param_area
;
3034 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3035 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3040 ppc_lwz (code
, ppc_r0
, 0, ppc_sp
);
3041 if (ppc_is_imm16 (-size
)) {
3042 ppc_stwu (code
, ppc_r0
, -size
, ppc_sp
);
3044 ppc_load (code
, ppc_r11
, -size
);
3045 ppc_stwux (code
, ppc_r0
, ppc_sp
, ppc_r11
);
3052 emit_unreserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3054 int size
= cfg
->param_area
;
3056 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3057 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3062 ppc_lwz (code
, ppc_r0
, 0, ppc_sp
);
3063 if (ppc_is_imm16 (size
)) {
3064 ppc_stwu (code
, ppc_r0
, size
, ppc_sp
);
3066 ppc_load (code
, ppc_r11
, size
);
3067 ppc_stwux (code
, ppc_r0
, ppc_sp
, ppc_r11
);
3074 mono_arch_output_basic_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
3079 guint8
*code
= cfg
->native_code
+ cfg
->code_len
;
3080 MonoInst
*last_ins
= NULL
;
3081 guint last_offset
= 0;
3085 /* we don't align basic blocks of loops on mips */
3087 if (cfg
->verbose_level
> 2)
3088 g_print ("Basic block %d starting at offset 0x%x\n", bb
->block_num
, bb
->native_offset
);
3090 cpos
= bb
->max_offset
;
3093 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
) {
3094 MonoCoverageInfo
*cov
= mono_get_coverage_info (cfg
->method
);
3095 g_assert (!mono_compile_aot
);
3098 cov
->data
[bb
->dfn
].iloffset
= bb
->cil_code
- cfg
->cil_code
;
3099 /* this is not thread save, but good enough */
3100 /* fixme: howto handle overflows? */
3101 mips_load_const (code
, mips_at
, &cov
->data
[bb
->dfn
].count
);
3102 mips_lw (code
, mips_temp
, mips_at
, 0);
3103 mips_addiu (code
, mips_temp
, mips_temp
, 1);
3104 mips_sw (code
, mips_temp
, mips_at
, 0);
3107 MONO_BB_FOR_EACH_INS (bb
, ins
) {
3108 offset
= code
- cfg
->native_code
;
3110 max_len
= ((guint8
*)ins_get_spec (ins
->opcode
))[MONO_INST_LEN
];
3112 if (offset
> (cfg
->code_size
- max_len
- 16)) {
3113 cfg
->code_size
*= 2;
3114 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
3115 code
= cfg
->native_code
+ offset
;
3117 mono_debug_record_line_number (cfg
, ins
, offset
);
3118 if (cfg
->verbose_level
> 2) {
3119 g_print (" @ 0x%x\t", offset
);
3120 mono_print_ins_index (ins_cnt
++, ins
);
3122 /* Check for virtual regs that snuck by */
3123 g_assert ((ins
->dreg
>= -1) && (ins
->dreg
< 32));
3125 switch (ins
->opcode
) {
3126 case OP_RELAXED_NOP
:
3129 case OP_DUMMY_STORE
:
3130 case OP_NOT_REACHED
:
3134 g_assert_not_reached();
3136 emit_tls_access (code
, ins
->dreg
, ins
->inst_offset
);
3140 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3141 mips_mflo (code
, ins
->dreg
);
3142 mips_mfhi (code
, ins
->dreg
+1);
3145 mips_multu (code
, ins
->sreg1
, ins
->sreg2
);
3146 mips_mflo (code
, ins
->dreg
);
3147 mips_mfhi (code
, ins
->dreg
+1);
3149 case OP_MEMORY_BARRIER
:
3154 case OP_STOREI1_MEMBASE_IMM
:
3155 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3156 if (mips_is_imm16 (ins
->inst_offset
)) {
3157 mips_sb (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3159 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3160 mips_sb (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3163 case OP_STOREI2_MEMBASE_IMM
:
3164 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3165 if (mips_is_imm16 (ins
->inst_offset
)) {
3166 mips_sh (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3168 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3169 mips_sh (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3172 case OP_STOREI8_MEMBASE_IMM
:
3173 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3174 if (mips_is_imm16 (ins
->inst_offset
)) {
3175 mips_sd (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3177 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3178 mips_sd (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3181 case OP_STORE_MEMBASE_IMM
:
3182 case OP_STOREI4_MEMBASE_IMM
:
3183 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3184 if (mips_is_imm16 (ins
->inst_offset
)) {
3185 mips_sw (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3187 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3188 mips_sw (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3191 case OP_STOREI1_MEMBASE_REG
:
3192 if (mips_is_imm16 (ins
->inst_offset
)) {
3193 mips_sb (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3195 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3196 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3197 mips_sb (code
, ins
->sreg1
, mips_at
, 0);
3200 case OP_STOREI2_MEMBASE_REG
:
3201 if (mips_is_imm16 (ins
->inst_offset
)) {
3202 mips_sh (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3204 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3205 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3206 mips_sh (code
, ins
->sreg1
, mips_at
, 0);
3209 case OP_STORE_MEMBASE_REG
:
3210 case OP_STOREI4_MEMBASE_REG
:
3211 if (mips_is_imm16 (ins
->inst_offset
)) {
3212 mips_sw (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3214 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3215 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3216 mips_sw (code
, ins
->sreg1
, mips_at
, 0);
3219 case OP_STOREI8_MEMBASE_REG
:
3220 if (mips_is_imm16 (ins
->inst_offset
)) {
3221 mips_sd (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3223 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3224 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3225 mips_sd (code
, ins
->sreg1
, mips_at
, 0);
3229 g_assert_not_reached ();
3230 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3231 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3233 case OP_LOADI8_MEMBASE
:
3234 if (mips_is_imm16 (ins
->inst_offset
)) {
3235 mips_ld (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3237 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3238 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3239 mips_ld (code
, ins
->dreg
, mips_at
, 0);
3242 case OP_LOAD_MEMBASE
:
3243 case OP_LOADI4_MEMBASE
:
3244 case OP_LOADU4_MEMBASE
:
3245 if (mips_is_imm16 (ins
->inst_offset
)) {
3246 mips_lw (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3248 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3249 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3250 mips_lw (code
, ins
->dreg
, mips_at
, 0);
3253 case OP_LOADI1_MEMBASE
:
3254 if (mips_is_imm16 (ins
->inst_offset
)) {
3255 mips_lb (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3257 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3258 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3259 mips_lb (code
, ins
->dreg
, mips_at
, 0);
3262 case OP_LOADU1_MEMBASE
:
3263 if (mips_is_imm16 (ins
->inst_offset
)) {
3264 mips_lbu (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3266 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3267 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3268 mips_lbu (code
, ins
->dreg
, mips_at
, 0);
3271 case OP_LOADI2_MEMBASE
:
3272 if (mips_is_imm16 (ins
->inst_offset
)) {
3273 mips_lh (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3275 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3276 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3277 mips_lh (code
, ins
->dreg
, mips_at
, 0);
3280 case OP_LOADU2_MEMBASE
:
3281 if (mips_is_imm16 (ins
->inst_offset
)) {
3282 mips_lhu (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3284 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3285 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3286 mips_lhu (code
, ins
->dreg
, mips_at
, 0);
3289 case OP_ICONV_TO_I1
:
3290 mips_sll (code
, mips_at
, ins
->sreg1
, 24);
3291 mips_sra (code
, ins
->dreg
, mips_at
, 24);
3293 case OP_ICONV_TO_I2
:
3294 mips_sll (code
, mips_at
, ins
->sreg1
, 16);
3295 mips_sra (code
, ins
->dreg
, mips_at
, 16);
3297 case OP_ICONV_TO_U1
:
3298 mips_andi (code
, ins
->dreg
, ins
->sreg1
, 0xff);
3300 case OP_ICONV_TO_U2
:
3301 mips_sll (code
, mips_at
, ins
->sreg1
, 16);
3302 mips_srl (code
, ins
->dreg
, mips_at
, 16);
3305 mips_slt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3308 g_assert (mips_is_imm16 (ins
->inst_imm
));
3309 mips_slti (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3312 mips_sltu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3315 g_assert (mips_is_imm16 (ins
->inst_imm
));
3316 mips_sltiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3319 mips_break (code
, 0xfd);
3322 mips_addu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3325 mips_daddu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3330 g_assert (mips_is_imm16 (ins
->inst_imm
));
3331 mips_addiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3334 g_assert (mips_is_imm16 (ins
->inst_imm
));
3335 mips_daddiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3339 mips_subu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3342 mips_dsubu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3347 // we add the negated value
3348 g_assert (mips_is_imm16 (-ins
->inst_imm
));
3349 mips_addiu (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
3353 // we add the negated value
3354 g_assert (mips_is_imm16 (-ins
->inst_imm
));
3355 mips_daddiu (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
3360 mips_and (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3366 g_assert (!(ins
->inst_imm
& 0xffff0000));
3367 mips_andi (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3372 guint32
*divisor_is_m1
;
3373 guint32
*divisor_is_zero
;
3376 mips_addiu (code
, mips_at
, mips_zero
, 0xffff);
3377 divisor_is_m1
= (guint32
*)(void *)code
;
3378 mips_bne (code
, ins
->sreg2
, mips_at
, 0);
3381 /* Divide by -1 -- throw exception */
3382 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
3384 mips_patch (divisor_is_m1
, (guint32
)code
);
3386 /* Put divide in branch delay slot (NOT YET) */
3387 divisor_is_zero
= (guint32
*)(void *)code
;
3388 mips_bne (code
, ins
->sreg2
, mips_zero
, 0);
3391 /* Divide by zero -- throw exception */
3392 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3394 mips_patch (divisor_is_zero
, (guint32
)code
);
3395 mips_div (code
, ins
->sreg1
, ins
->sreg2
);
3396 if (ins
->opcode
== OP_IDIV
)
3397 mips_mflo (code
, ins
->dreg
);
3399 mips_mfhi (code
, ins
->dreg
);
3404 guint32
*divisor_is_zero
= (guint32
*)(void *)code
;
3406 /* Put divide in branch delay slot (NOT YET) */
3407 mips_bne (code
, ins
->sreg2
, mips_zero
, 0);
3410 /* Divide by zero -- throw exception */
3411 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3413 mips_patch (divisor_is_zero
, (guint32
)code
);
3414 mips_divu (code
, ins
->sreg1
, ins
->sreg2
);
3415 if (ins
->opcode
== OP_IDIV_UN
)
3416 mips_mflo (code
, ins
->dreg
);
3418 mips_mfhi (code
, ins
->dreg
);
3422 g_assert_not_reached ();
3424 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
3425 ppc_divwod (code
, ins
->dreg
, ins
->sreg1
, ppc_r11
);
3426 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3427 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3428 /* FIXME: use OverflowException for 0x80000000/-1 */
3429 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
3431 g_assert_not_reached();
3434 g_assert_not_reached ();
3436 mips_or (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3440 g_assert (!(ins
->inst_imm
& 0xffff0000));
3441 mips_ori (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3444 mips_xor (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3448 /* unsigned 16-bit immediate */
3449 g_assert (!(ins
->inst_imm
& 0xffff0000));
3450 mips_xori (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3453 mips_sllv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3457 mips_sll (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3460 mips_srav (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3463 mips_dsrav (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3467 mips_sra (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3470 mips_dsra (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x3f);
3473 case OP_ISHR_UN_IMM
:
3474 mips_srl (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3476 case OP_LSHR_UN_IMM
:
3477 mips_dsrl (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x3f);
3480 mips_srlv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3483 mips_dsrlv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3487 mips_nor (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3490 mips_subu (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3493 mips_dsubu (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3497 mips_mul (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3499 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3500 mips_mflo (code
, ins
->dreg
);
3505 #if SIZEOF_REGISTER == 8
3507 mips_dmult (code
, ins
->sreg1
, ins
->sreg2
);
3508 mips_mflo (code
, ins
->dreg
);
3513 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3514 mips_mflo (code
, ins
->dreg
);
3515 mips_mfhi (code
, mips_at
);
3518 mips_sra (code
, mips_temp
, ins
->dreg
, 31);
3519 patch
= (guint32
*)(void *)code
;
3520 mips_beq (code
, mips_temp
, mips_at
, 0);
3522 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3523 mips_patch (patch
, (guint32
)code
);
3526 case OP_IMUL_OVF_UN
:
3528 mips_mul (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3530 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3531 mips_mflo (code
, ins
->dreg
);
3532 mips_mfhi (code
, mips_at
);
3536 /* XXX - Throw exception if we overflowed */
3539 mips_load_const (code
, ins
->dreg
, ins
->inst_c0
);
3541 #if SIZEOF_REGISTER == 8
3543 mips_load_const (code
, ins
->dreg
, ins
->inst_c0
);
3547 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_i1
, ins
->inst_p0
);
3548 mips_load (code
, ins
->dreg
, 0);
3552 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3554 case OP_MIPS_MTC1S_2
:
3555 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3556 mips_mtc1 (code
, ins
->dreg
+1, ins
->sreg2
);
3559 mips_mfc1 (code
, ins
->dreg
, ins
->sreg1
);
3562 mips_dmtc1 (code
, ins
->dreg
, ins
->sreg1
);
3566 mips_dmfc1 (code
, ins
->dreg
, ins
->sreg1
);
3568 mips_mfc1 (code
, ins
->dreg
+1, ins
->sreg1
);
3569 mips_mfc1 (code
, ins
->dreg
, ins
->sreg1
+1);
3573 case OP_ICONV_TO_I4
:
3574 case OP_ICONV_TO_U4
:
3576 if (ins
->dreg
!= ins
->sreg1
)
3577 MIPS_MOVE (code
, ins
->dreg
, ins
->sreg1
);
3579 #if SIZEOF_REGISTER == 8
3581 mips_dsll (code
, ins
->dreg
, ins
->sreg1
, 32);
3582 mips_dsrl (code
, ins
->dreg
, ins
->dreg
, 32);
3585 mips_dsll (code
, ins
->dreg
, ins
->sreg1
, 32);
3586 mips_dsra (code
, ins
->dreg
, ins
->dreg
, 32);
3590 /* Get sreg1 into v1, sreg2 into v0 */
3592 if (ins
->sreg1
== mips_v0
) {
3593 if (ins
->sreg1
!= mips_at
)
3594 MIPS_MOVE (code
, mips_at
, ins
->sreg1
);
3595 if (ins
->sreg2
!= mips_v0
)
3596 MIPS_MOVE (code
, mips_v0
, ins
->sreg2
);
3597 MIPS_MOVE (code
, mips_v1
, mips_at
);
3600 if (ins
->sreg2
!= mips_v0
)
3601 MIPS_MOVE (code
, mips_v0
, ins
->sreg2
);
3602 if (ins
->sreg1
!= mips_v1
)
3603 MIPS_MOVE (code
, mips_v1
, ins
->sreg1
);
3607 if (ins
->dreg
!= ins
->sreg1
) {
3608 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
3612 /* Convert from double to float and leave it there */
3613 mips_cvtsd (code
, ins
->dreg
, ins
->sreg1
);
3615 case OP_FCONV_TO_R4
:
3617 mips_cvtsd (code
, ins
->dreg
, ins
->sreg1
);
3619 /* Just a move, no precision change */
3620 if (ins
->dreg
!= ins
->sreg1
) {
3621 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
3626 code
= emit_load_volatile_arguments(cfg
, code
);
3629 * Pop our stack, then jump to specified method (tail-call)
3630 * Keep in sync with mono_arch_emit_epilog
3632 code
= mono_arch_emit_epilog_sub (cfg
, code
);
3634 mono_add_patch_info (cfg
, (guint8
*) code
- cfg
->native_code
,
3635 MONO_PATCH_INFO_METHOD_JUMP
, ins
->inst_p0
);
3637 mips_lui (code
, mips_t9
, mips_zero
, 0);
3638 mips_addiu (code
, mips_t9
, mips_t9
, 0);
3639 mips_jr (code
, mips_t9
);
3642 mips_beq (code
, mips_zero
, mips_zero
, 0);
3647 /* ensure ins->sreg1 is not NULL */
3648 mips_lw (code
, mips_zero
, ins
->sreg1
, 0);
3651 if (mips_is_imm16 (cfg
->sig_cookie
+ cfg
->stack_usage
)) {
3652 mips_addiu (code
, mips_at
, cfg
->frame_reg
, cfg
->sig_cookie
+ cfg
->stack_usage
);
3654 mips_load_const (code
, mips_at
, cfg
->sig_cookie
+ cfg
->stack_usage
);
3655 mips_addu (code
, mips_at
, cfg
->frame_reg
, mips_at
);
3657 mips_sw (code
, mips_at
, ins
->sreg1
, 0);
3670 case OP_VOIDCALL_REG
:
3672 case OP_FCALL_MEMBASE
:
3673 case OP_LCALL_MEMBASE
:
3674 case OP_VCALL_MEMBASE
:
3675 case OP_VCALL2_MEMBASE
:
3676 case OP_VOIDCALL_MEMBASE
:
3677 case OP_CALL_MEMBASE
:
3678 call
= (MonoCallInst
*)ins
;
3679 switch (ins
->opcode
) {
3686 if (ins
->flags
& MONO_INST_HAS_METHOD
)
3687 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_METHOD
, call
->method
);
3689 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_ABS
, call
->fptr
);
3690 mips_lui (code
, mips_t9
, mips_zero
, 0);
3691 mips_addiu (code
, mips_t9
, mips_t9
, 0);
3697 case OP_VOIDCALL_REG
:
3699 MIPS_MOVE (code
, mips_t9
, ins
->sreg1
);
3701 case OP_FCALL_MEMBASE
:
3702 case OP_LCALL_MEMBASE
:
3703 case OP_VCALL_MEMBASE
:
3704 case OP_VCALL2_MEMBASE
:
3705 case OP_VOIDCALL_MEMBASE
:
3706 case OP_CALL_MEMBASE
:
3707 mips_lw (code
, mips_t9
, ins
->sreg1
, ins
->inst_offset
);
3710 mips_jalr (code
, mips_t9
, mips_ra
);
3712 #if PROMOTE_R4_TO_R8
3713 /* returned an FP R4 (single), promote to R8 (double) in place */
3714 if ((ins
->opcode
== OP_FCALL
||
3715 ins
->opcode
== OP_FCALL_REG
) &&
3716 call
->signature
->ret
->type
== MONO_TYPE_R4
) {
3717 mips_cvtds (code
, mips_f0
, mips_f0
);
3722 int area_offset
= cfg
->param_area
;
3724 /* Round up ins->sreg1, mips_at ends up holding size */
3725 mips_addiu (code
, mips_at
, ins
->sreg1
, 31);
3726 mips_addiu (code
, mips_temp
, mips_zero
, ~31);
3727 mips_and (code
, mips_at
, mips_at
, mips_temp
);
3729 mips_subu (code
, mips_sp
, mips_sp
, mips_at
);
3730 g_assert (mips_is_imm16 (area_offset
));
3731 mips_addiu (code
, ins
->dreg
, mips_sp
, area_offset
);
3733 if (ins
->flags
& MONO_INST_INIT
) {
3734 mips_move (code
, mips_temp
, ins
->dreg
);
3735 mips_sb (code
, mips_zero
, mips_temp
, 0);
3736 mips_addiu (code
, mips_at
, mips_at
, -1);
3737 mips_bne (code
, mips_at
, mips_zero
, -3);
3738 mips_addiu (code
, mips_temp
, mips_temp
, 1);
3743 gpointer addr
= mono_arch_get_throw_exception(NULL
, FALSE
);
3744 mips_move (code
, mips_a0
, ins
->sreg1
);
3745 mips_load_const (code
, mips_t9
, addr
);
3746 mips_jalr (code
, mips_t9
, mips_ra
);
3748 mips_break (code
, 0xfc);
3752 gpointer addr
= mono_arch_get_rethrow_exception(NULL
, FALSE
);
3753 mips_move (code
, mips_a0
, ins
->sreg1
);
3754 mips_load_const (code
, mips_t9
, addr
);
3755 mips_jalr (code
, mips_t9
, mips_ra
);
3757 mips_break (code
, 0xfb);
3760 case OP_START_HANDLER
: {
3762 * The START_HANDLER instruction marks the beginning of
3763 * a handler block. It is called using a call
3764 * instruction, so mips_ra contains the return address.
3765 * Since the handler executes in the same stack frame
3766 * as the method itself, we can't use save/restore to
3767 * save the return address. Instead, we save it into
3768 * a dedicated variable.
3770 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3771 g_assert (spvar
->inst_basereg
!= mips_sp
);
3772 code
= emit_reserve_param_area (cfg
, code
);
3774 if (mips_is_imm16 (spvar
->inst_offset
)) {
3775 mips_sw (code
, mips_ra
, spvar
->inst_basereg
, spvar
->inst_offset
);
3777 mips_load_const (code
, mips_at
, spvar
->inst_offset
);
3778 mips_addu (code
, mips_at
, mips_at
, spvar
->inst_basereg
);
3779 mips_sw (code
, mips_ra
, mips_at
, 0);
3783 case OP_ENDFILTER
: {
3784 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3785 g_assert (spvar
->inst_basereg
!= mips_sp
);
3786 code
= emit_unreserve_param_area (cfg
, code
);
3788 if (ins
->sreg1
!= mips_v0
)
3789 MIPS_MOVE (code
, mips_v0
, ins
->sreg1
);
3790 if (mips_is_imm16 (spvar
->inst_offset
)) {
3791 mips_lw (code
, mips_ra
, spvar
->inst_basereg
, spvar
->inst_offset
);
3793 mips_load_const (code
, mips_at
, spvar
->inst_offset
);
3794 mips_addu (code
, mips_at
, mips_at
, spvar
->inst_basereg
);
3795 mips_lw (code
, mips_ra
, mips_at
, 0);
3797 mips_jr (code
, mips_ra
);
3801 case OP_ENDFINALLY
: {
3802 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3803 g_assert (spvar
->inst_basereg
!= mips_sp
);
3804 code
= emit_unreserve_param_area (cfg
, code
);
3805 mips_lw (code
, mips_t9
, spvar
->inst_basereg
, spvar
->inst_offset
);
3806 mips_jalr (code
, mips_t9
, mips_ra
);
3810 case OP_CALL_HANDLER
:
3811 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
3812 mips_lui (code
, mips_t9
, mips_zero
, 0);
3813 mips_addiu (code
, mips_t9
, mips_t9
, 0);
3814 mips_jalr (code
, mips_t9
, mips_ra
);
3816 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3817 mono_cfg_add_try_hole (cfg
, ins
->inst_eh_block
, code
, bb
);
3820 ins
->inst_c0
= code
- cfg
->native_code
;
3823 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
3825 mips_lui (code
, mips_at
, mips_zero
, 0);
3826 mips_addiu (code
, mips_at
, mips_at
, 0);
3827 mips_jr (code
, mips_at
);
3830 mips_beq (code
, mips_zero
, mips_zero
, 0);
3835 mips_jr (code
, ins
->sreg1
);
3841 max_len
+= 4 * GPOINTER_TO_INT (ins
->klass
);
3842 if (offset
> (cfg
->code_size
- max_len
- 16)) {
3843 cfg
->code_size
+= max_len
;
3844 cfg
->code_size
*= 2;
3845 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
3846 code
= cfg
->native_code
+ offset
;
3848 g_assert (ins
->sreg1
!= -1);
3849 mips_sll (code
, mips_at
, ins
->sreg1
, 2);
3850 if (1 || !(cfg
->flags
& MONO_CFG_HAS_CALLS
))
3851 MIPS_MOVE (code
, mips_t8
, mips_ra
);
3852 mips_bgezal (code
, mips_zero
, 1); /* bal */
3854 mips_addu (code
, mips_t9
, mips_ra
, mips_at
);
3855 /* Table is 16 or 20 bytes from target of bal above */
3856 if (1 || !(cfg
->flags
& MONO_CFG_HAS_CALLS
)) {
3857 MIPS_MOVE (code
, mips_ra
, mips_t8
);
3858 mips_lw (code
, mips_t9
, mips_t9
, 20);
3861 mips_lw (code
, mips_t9
, mips_t9
, 16);
3862 mips_jalr (code
, mips_t9
, mips_t8
);
3864 for (i
= 0; i
< GPOINTER_TO_INT (ins
->klass
); ++i
)
3865 mips_emit32 (code
, 0xfefefefe);
3870 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
3871 mips_beq (code
, mips_at
, mips_zero
, 2);
3873 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
3879 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
3880 mips_bltz (code
, mips_at
, 2);
3882 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
3888 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
3889 mips_bgtz (code
, mips_at
, 2);
3891 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
3894 case OP_MIPS_COND_EXC_EQ
:
3895 case OP_MIPS_COND_EXC_GE
:
3896 case OP_MIPS_COND_EXC_GT
:
3897 case OP_MIPS_COND_EXC_LE
:
3898 case OP_MIPS_COND_EXC_LT
:
3899 case OP_MIPS_COND_EXC_NE_UN
:
3900 case OP_MIPS_COND_EXC_GE_UN
:
3901 case OP_MIPS_COND_EXC_GT_UN
:
3902 case OP_MIPS_COND_EXC_LE_UN
:
3903 case OP_MIPS_COND_EXC_LT_UN
:
3905 case OP_MIPS_COND_EXC_OV
:
3906 case OP_MIPS_COND_EXC_NO
:
3907 case OP_MIPS_COND_EXC_C
:
3908 case OP_MIPS_COND_EXC_NC
:
3910 case OP_MIPS_COND_EXC_IEQ
:
3911 case OP_MIPS_COND_EXC_IGE
:
3912 case OP_MIPS_COND_EXC_IGT
:
3913 case OP_MIPS_COND_EXC_ILE
:
3914 case OP_MIPS_COND_EXC_ILT
:
3915 case OP_MIPS_COND_EXC_INE_UN
:
3916 case OP_MIPS_COND_EXC_IGE_UN
:
3917 case OP_MIPS_COND_EXC_IGT_UN
:
3918 case OP_MIPS_COND_EXC_ILE_UN
:
3919 case OP_MIPS_COND_EXC_ILT_UN
:
3921 case OP_MIPS_COND_EXC_IOV
:
3922 case OP_MIPS_COND_EXC_INO
:
3923 case OP_MIPS_COND_EXC_IC
:
3924 case OP_MIPS_COND_EXC_INC
: {
3928 /* If the condition is true, raise the exception */
3930 /* need to reverse test to skip around exception raising */
3932 /* For the moment, branch around a branch to avoid reversing
3935 /* Remember, an unpatched branch to 0 branches to the delay slot */
3936 switch (ins
->opcode
) {
3937 case OP_MIPS_COND_EXC_EQ
:
3938 throw = (guint32
*)(void *)code
;
3939 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, 0);
3943 case OP_MIPS_COND_EXC_NE_UN
:
3944 throw = (guint32
*)(void *)code
;
3945 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, 0);
3949 case OP_MIPS_COND_EXC_LE_UN
:
3950 mips_subu (code
, mips_at
, ins
->sreg1
, ins
->sreg2
);
3951 throw = (guint32
*)(void *)code
;
3952 mips_blez (code
, mips_at
, 0);
3956 case OP_MIPS_COND_EXC_GT
:
3957 mips_slt (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
3958 throw = (guint32
*)(void *)code
;
3959 mips_bne (code
, mips_at
, mips_zero
, 0);
3963 case OP_MIPS_COND_EXC_GT_UN
:
3964 mips_sltu (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
3965 throw = (guint32
*)(void *)code
;
3966 mips_bne (code
, mips_at
, mips_zero
, 0);
3970 case OP_MIPS_COND_EXC_LT
:
3971 mips_slt (code
, mips_at
, ins
->sreg1
, ins
->sreg2
);
3972 throw = (guint32
*)(void *)code
;
3973 mips_bne (code
, mips_at
, mips_zero
, 0);
3977 case OP_MIPS_COND_EXC_LT_UN
:
3978 mips_sltu (code
, mips_at
, ins
->sreg1
, ins
->sreg2
);
3979 throw = (guint32
*)(void *)code
;
3980 mips_bne (code
, mips_at
, mips_zero
, 0);
3985 /* Not yet implemented */
3986 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins
->opcode
));
3987 g_assert_not_reached ();
3989 skip
= (guint32
*)(void *)code
;
3990 mips_beq (code
, mips_zero
, mips_zero
, 0);
3992 mips_patch (throw, (guint32
)code
);
3993 code
= mips_emit_exc_by_name (code
, ins
->inst_p1
);
3994 mips_patch (skip
, (guint32
)code
);
3995 cfg
->bb_exit
->max_offset
+= 24;
4004 code
= mips_emit_cond_branch (cfg
, code
, ins
->opcode
, ins
);
4007 /* floating point opcodes */
4010 if (((guint32
)ins
->inst_p0
) & (1 << 15))
4011 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16)+1);
4013 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16));
4014 mips_ldc1 (code
, ins
->dreg
, mips_at
, ((guint32
)ins
->inst_p0
) & 0xffff);
4016 mips_load_const (code
, mips_at
, ins
->inst_p0
);
4017 mips_lwc1 (code
, ins
->dreg
, mips_at
, 4);
4018 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, 0);
4022 if (((guint32
)ins
->inst_p0
) & (1 << 15))
4023 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16)+1);
4025 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16));
4026 mips_lwc1 (code
, ins
->dreg
, mips_at
, ((guint32
)ins
->inst_p0
) & 0xffff);
4027 #if PROMOTE_R4_TO_R8
4028 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4031 case OP_STORER8_MEMBASE_REG
:
4032 if (mips_is_imm16 (ins
->inst_offset
)) {
4033 #if _MIPS_SIM == _ABIO32
4034 mips_swc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
+4);
4035 mips_swc1 (code
, ins
->sreg1
+1, ins
->inst_destbasereg
, ins
->inst_offset
);
4036 #elif _MIPS_SIM == _ABIN32
4037 mips_sdc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
4040 mips_load_const (code
, mips_at
, ins
->inst_offset
);
4041 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
4042 mips_swc1 (code
, ins
->sreg1
, mips_at
, 4);
4043 mips_swc1 (code
, ins
->sreg1
+1, mips_at
, 0);
4046 case OP_LOADR8_MEMBASE
:
4047 if (mips_is_imm16 (ins
->inst_offset
)) {
4048 #if _MIPS_SIM == _ABIO32
4049 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
+4);
4050 mips_lwc1 (code
, ins
->dreg
+1, ins
->inst_basereg
, ins
->inst_offset
);
4051 #elif _MIPS_SIM == _ABIN32
4052 mips_ldc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4055 mips_load_const (code
, mips_at
, ins
->inst_offset
);
4056 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
4057 mips_lwc1 (code
, ins
->dreg
, mips_at
, 4);
4058 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, 0);
4061 case OP_STORER4_MEMBASE_REG
:
4062 g_assert (mips_is_imm16 (ins
->inst_offset
));
4063 #if PROMOTE_R4_TO_R8
4064 /* Need to convert ins->sreg1 to single-precision first */
4065 mips_cvtsd (code
, mips_ftemp
, ins
->sreg1
);
4067 mips_swc1 (code
, mips_ftemp
, ins
->inst_destbasereg
, ins
->inst_offset
);
4070 g_assert (mips_is_imm16 (ins
->inst_offset
));
4071 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4073 case OP_LOADR4_MEMBASE
:
4074 g_assert (mips_is_imm16 (ins
->inst_offset
));
4075 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4076 #if PROMOTE_R4_TO_R8
4077 /* Convert to double precision in place */
4078 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4081 case OP_ICONV_TO_R_UN
: {
4082 static const guint64 adjust_val
= 0x41F0000000000000ULL
;
4084 /* convert unsigned int to double */
4085 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4086 mips_bgez (code
, ins
->sreg1
, 5);
4087 mips_cvtdw (code
, ins
->dreg
, mips_ftemp
);
4089 mips_load (code
, mips_at
, (guint32
) &adjust_val
);
4090 mips_ldc1 (code
, mips_ftemp
, mips_at
, 0);
4091 mips_faddd (code
, ins
->dreg
, ins
->dreg
, mips_ftemp
);
4092 /* target is here */
4095 case OP_ICONV_TO_R4
:
4096 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4097 mips_cvtsw (code
, ins
->dreg
, mips_ftemp
);
4098 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4100 case OP_ICONV_TO_R8
:
4101 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4102 mips_cvtdw (code
, ins
->dreg
, mips_ftemp
);
4104 case OP_FCONV_TO_I1
:
4105 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, TRUE
);
4107 case OP_FCONV_TO_U1
:
4108 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, FALSE
);
4110 case OP_FCONV_TO_I2
:
4111 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, TRUE
);
4113 case OP_FCONV_TO_U2
:
4114 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, FALSE
);
4116 case OP_FCONV_TO_I4
:
4118 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, TRUE
);
4120 case OP_FCONV_TO_U4
:
4122 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, FALSE
);
4125 mips_fsqrtd (code
, ins
->dreg
, ins
->sreg1
);
4128 mips_faddd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4131 mips_fsubd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4134 mips_fmuld (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4137 mips_fdivd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4140 mips_fnegd (code
, ins
->dreg
, ins
->sreg1
);
4143 mips_fcmpd (code
, MIPS_FPU_EQ
, ins
->sreg1
, ins
->sreg2
);
4144 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4145 mips_fbtrue (code
, 2);
4147 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4150 mips_fcmpd (code
, MIPS_FPU_LT
, ins
->sreg1
, ins
->sreg2
);
4151 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4152 mips_fbtrue (code
, 2);
4154 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4157 /* Less than, or Unordered */
4158 mips_fcmpd (code
, MIPS_FPU_ULT
, ins
->sreg1
, ins
->sreg2
);
4159 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4160 mips_fbtrue (code
, 2);
4162 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4165 mips_fcmpd (code
, MIPS_FPU_ULE
, ins
->sreg1
, ins
->sreg2
);
4166 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4167 mips_fbtrue (code
, 2);
4169 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4172 /* Greater than, or Unordered */
4173 mips_fcmpd (code
, MIPS_FPU_OLE
, ins
->sreg1
, ins
->sreg2
);
4174 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4175 mips_fbtrue (code
, 2);
4177 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4180 mips_fcmpd (code
, MIPS_FPU_EQ
, ins
->sreg1
, ins
->sreg2
);
4182 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4183 mips_fbtrue (code
, 0);
4187 mips_fcmpd (code
, MIPS_FPU_EQ
, ins
->sreg1
, ins
->sreg2
);
4189 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4190 mips_fbfalse (code
, 0);
4194 mips_fcmpd (code
, MIPS_FPU_LT
, ins
->sreg1
, ins
->sreg2
);
4196 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4197 mips_fbtrue (code
, 0);
4200 case OP_MIPS_FBLT_UN
:
4201 mips_fcmpd (code
, MIPS_FPU_ULT
, ins
->sreg1
, ins
->sreg2
);
4203 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4204 mips_fbtrue (code
, 0);
4208 mips_fcmpd (code
, MIPS_FPU_LE
, ins
->sreg1
, ins
->sreg2
);
4210 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4211 mips_fbfalse (code
, 0);
4214 case OP_MIPS_FBGT_UN
:
4215 mips_fcmpd (code
, MIPS_FPU_OLE
, ins
->sreg1
, ins
->sreg2
);
4217 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4218 mips_fbfalse (code
, 0);
4222 mips_fcmpd (code
, MIPS_FPU_LT
, ins
->sreg1
, ins
->sreg2
);
4224 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4225 mips_fbfalse (code
, 0);
4228 case OP_MIPS_FBGE_UN
:
4229 mips_fcmpd (code
, MIPS_FPU_OLT
, ins
->sreg1
, ins
->sreg2
);
4231 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4232 mips_fbfalse (code
, 0);
4236 mips_fcmpd (code
, MIPS_FPU_OLE
, ins
->sreg1
, ins
->sreg2
);
4238 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4239 mips_fbtrue (code
, 0);
4242 case OP_MIPS_FBLE_UN
:
4243 mips_fcmpd (code
, MIPS_FPU_ULE
, ins
->sreg1
, ins
->sreg2
);
4245 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4246 mips_fbtrue (code
, 0);
4250 guint32
*branch_patch
;
4252 mips_mfc1 (code
, mips_at
, ins
->sreg1
+1);
4253 mips_srl (code
, mips_at
, mips_at
, 16+4);
4254 mips_andi (code
, mips_at
, mips_at
, 2047);
4255 mips_addiu (code
, mips_at
, mips_at
, -2047);
4257 branch_patch
= (guint32
*)(void *)code
;
4258 mips_bne (code
, mips_at
, mips_zero
, 0);
4261 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4262 mips_patch (branch_patch
, (guint32
)code
);
4263 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
4267 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_c1
, ins
->inst_p0
);
4268 mips_load (code
, ins
->dreg
, 0x0f0f0f0f);
4273 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins
->opcode
), __FUNCTION__
);
4274 g_assert_not_reached ();
4277 if ((cfg
->opt
& MONO_OPT_BRANCH
) && ((code
- cfg
->native_code
- offset
) > max_len
)) {
4278 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4279 mono_inst_name (ins
->opcode
), max_len
, code
- cfg
->native_code
- offset
);
4280 g_assert_not_reached ();
4286 last_offset
= offset
;
4289 cfg
->code_len
= code
- cfg
->native_code
;
4293 mono_arch_register_lowlevel_calls (void)
4298 mono_arch_patch_code (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*ji
, gboolean run_cctors
)
4300 MonoJumpInfo
*patch_info
;
4302 for (patch_info
= ji
; patch_info
; patch_info
= patch_info
->next
) {
4303 unsigned char *ip
= patch_info
->ip
.i
+ code
;
4304 const unsigned char *target
= NULL
;
4306 switch (patch_info
->type
) {
4307 case MONO_PATCH_INFO_IP
:
4308 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)ip
);
4310 case MONO_PATCH_INFO_SWITCH
: {
4311 gpointer
*table
= (gpointer
*)patch_info
->data
.table
->table
;
4314 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)table
);
4316 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
4317 table
[i
] = (int)patch_info
->data
.table
->table
[i
] + code
;
4321 case MONO_PATCH_INFO_METHODCONST
:
4322 case MONO_PATCH_INFO_CLASS
:
4323 case MONO_PATCH_INFO_IMAGE
:
4324 case MONO_PATCH_INFO_FIELD
:
4325 case MONO_PATCH_INFO_VTABLE
:
4326 case MONO_PATCH_INFO_IID
:
4327 case MONO_PATCH_INFO_SFLDA
:
4328 case MONO_PATCH_INFO_LDSTR
:
4329 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
4330 case MONO_PATCH_INFO_LDTOKEN
:
4331 case MONO_PATCH_INFO_R4
:
4332 case MONO_PATCH_INFO_R8
:
4333 /* from OP_AOTCONST : lui + addiu */
4334 target
= mono_resolve_patch_target (method
, domain
, code
, patch_info
, run_cctors
);
4335 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)target
);
4338 case MONO_PATCH_INFO_EXC_NAME
:
4339 g_assert_not_reached ();
4340 *((gconstpointer
*)(void *)(ip
+ 1)) = patch_info
->data
.name
;
4343 case MONO_PATCH_INFO_NONE
:
4344 /* everything is dealt with at epilog output time */
4347 target
= mono_resolve_patch_target (method
, domain
, code
, patch_info
, run_cctors
);
4348 mips_patch ((guint32
*)(void *)ip
, (guint32
)target
);
4357 mono_trace_lmf_prolog (MonoLMF
*new_lmf
)
4363 mono_trace_lmf_epilog (MonoLMF
*old_lmf
)
4369 * Allow tracing to work with this interface (with an optional argument)
4371 * This code is expected to be inserted just after the 'real' prolog code,
4372 * and before the first basic block. We need to allocate a 2nd, temporary
4373 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4377 mono_arch_instrument_prolog (MonoCompile
*cfg
, void *func
, void *p
, gboolean enable_arguments
)
4380 int offset
= cfg
->arch
.tracing_offset
;
4386 /* For N32, need to know for each stack slot if it's an integer
4387 * or float argument, and save/restore the appropriate register
4389 MIPS_SW (code
, mips_a0
, mips_sp
, offset
+ 0*SIZEOF_REGISTER
);
4390 MIPS_SW (code
, mips_a1
, mips_sp
, offset
+ 1*SIZEOF_REGISTER
);
4391 MIPS_SW (code
, mips_a2
, mips_sp
, offset
+ 2*SIZEOF_REGISTER
);
4392 MIPS_SW (code
, mips_a3
, mips_sp
, offset
+ 3*SIZEOF_REGISTER
);
4393 #if _MIPS_SIM == _ABIN32
4394 MIPS_SW (code
, mips_a4
, mips_sp
, offset
+ 4*SIZEOF_REGISTER
);
4395 MIPS_SW (code
, mips_a5
, mips_sp
, offset
+ 5*SIZEOF_REGISTER
);
4396 MIPS_SW (code
, mips_a6
, mips_sp
, offset
+ 6*SIZEOF_REGISTER
);
4397 MIPS_SW (code
, mips_a7
, mips_sp
, offset
+ 7*SIZEOF_REGISTER
);
4400 mips_load_const (code
, mips_a0
, cfg
->method
);
4401 mips_addiu (code
, mips_a1
, mips_sp
, offset
);
4402 mips_load_const (code
, mips_t9
, func
);
4403 mips_jalr (code
, mips_t9
, mips_ra
);
4406 MIPS_LW (code
, mips_a0
, mips_sp
, offset
+ 0*SIZEOF_REGISTER
);
4407 MIPS_LW (code
, mips_a1
, mips_sp
, offset
+ 1*SIZEOF_REGISTER
);
4408 MIPS_LW (code
, mips_a2
, mips_sp
, offset
+ 2*SIZEOF_REGISTER
);
4409 MIPS_LW (code
, mips_a3
, mips_sp
, offset
+ 3*SIZEOF_REGISTER
);
4410 #if _MIPS_SIM == _ABIN32
4411 MIPS_LW (code
, mips_a4
, mips_sp
, offset
+ 4*SIZEOF_REGISTER
);
4412 MIPS_LW (code
, mips_a5
, mips_sp
, offset
+ 5*SIZEOF_REGISTER
);
4413 MIPS_LW (code
, mips_a6
, mips_sp
, offset
+ 6*SIZEOF_REGISTER
);
4414 MIPS_LW (code
, mips_a7
, mips_sp
, offset
+ 7*SIZEOF_REGISTER
);
4424 mips_adjust_stackframe(MonoCompile
*cfg
)
4427 int delta
, threshold
, i
;
4428 MonoMethodSignature
*sig
;
4431 if (cfg
->stack_offset
== cfg
->arch
.local_alloc_offset
)
4434 /* adjust cfg->stack_offset for account for down-spilling */
4435 cfg
->stack_offset
+= SIZEOF_REGISTER
;
4437 /* re-align cfg->stack_offset if needed (due to var spilling) */
4438 cfg
->stack_offset
= (cfg
->stack_offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
4439 delta
= cfg
->stack_offset
- cfg
->arch
.local_alloc_offset
;
4440 if (cfg
->verbose_level
> 2) {
4441 g_print ("mips_adjust_stackframe:\n");
4442 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg
->arch
.local_alloc_offset
, cfg
->stack_offset
);
4444 threshold
= cfg
->arch
.local_alloc_offset
;
4445 ra_offset
= cfg
->stack_offset
- sizeof(gpointer
);
4446 if (cfg
->verbose_level
> 2) {
4447 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset
, ra_offset
, delta
, delta
);
4450 sig
= mono_method_signature (cfg
->method
);
4451 if (sig
&& sig
->ret
&& MONO_TYPE_ISSTRUCT (sig
->ret
)) {
4452 cfg
->vret_addr
->inst_offset
+= delta
;
4454 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4455 MonoInst
*inst
= cfg
->args
[i
];
4457 inst
->inst_offset
+= delta
;
4461 * loads and stores based off the frame reg that (used to) lie
4462 * above the spill var area need to be increased by 'delta'
4463 * to make room for the spill vars.
4465 /* Need to find loads and stores to adjust that
4466 * are above where the spillvars were inserted, but
4467 * which are not the spillvar references themselves.
4469 * Idea - since all offsets from fp are positive, make
4470 * spillvar offsets negative to begin with so we can spot
4475 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
4479 if (cfg
->verbose_level
> 2) {
4480 g_print ("BASIC BLOCK %d:\n", bb
->block_num
);
4482 MONO_BB_FOR_EACH_INS (bb
, ins
) {
4486 if (cfg
->verbose_level
> 2) {
4487 mono_print_ins_index (ins_cnt
, ins
);
4489 if (MONO_IS_LOAD_MEMBASE(ins
) && (ins
->inst_basereg
== mips_fp
))
4491 if (MONO_IS_STORE_MEMBASE(ins
) && (ins
->dreg
== mips_fp
))
4493 /* The following two catch FP spills */
4494 if (MONO_IS_LOAD_MEMBASE(ins
) && (ins
->inst_basereg
== mips_sp
))
4496 if (MONO_IS_STORE_MEMBASE(ins
) && (ins
->dreg
== mips_sp
))
4498 if (((ins
->opcode
== OP_ADD_IMM
) || (ins
->opcode
== OP_IADD_IMM
)) && (ins
->sreg1
== mips_fp
))
4501 if (ins
->inst_c0
>= threshold
) {
4502 ins
->inst_c0
+= delta
;
4503 if (cfg
->verbose_level
> 2) {
4505 mono_print_ins_index (ins_cnt
, ins
);
4508 else if (ins
->inst_c0
< 0) {
4509 ins
->inst_c0
= - ins
->inst_c0
- 4;
4510 if (cfg
->verbose_level
> 2) {
4512 mono_print_ins_index (ins_cnt
, ins
);
4515 g_assert (ins
->inst_c0
!= ra_offset
);
4518 if (ins
->inst_imm
>= threshold
) {
4519 ins
->inst_imm
+= delta
;
4520 if (cfg
->verbose_level
> 2) {
4522 mono_print_ins_index (ins_cnt
, ins
);
4525 g_assert (ins
->inst_c0
!= ra_offset
);
4535 * Stack frame layout:
4537 * ------------------- sp + cfg->stack_usage + cfg->param_area
4538 * param area incoming
4539 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4541 * ------------------- sp + cfg->stack_usage
4543 * ------------------- sp + cfg->stack_usage-4
4545 * ------------------- sp +
4546 * MonoLMF structure optional
4547 * ------------------- sp + cfg->arch.lmf_offset
4548 * saved registers s0-s8
4549 * ------------------- sp + cfg->arch.iregs_offset
4551 * ------------------- sp + cfg->param_area
4552 * param area outgoing
4553 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4555 * ------------------- sp
4559 mono_arch_emit_prolog (MonoCompile
*cfg
)
4561 MonoMethod
*method
= cfg
->method
;
4562 MonoMethodSignature
*sig
;
4564 int alloc_size
, pos
, i
;
4568 guint32 iregs_to_save
= 0;
4570 guint32 fregs_to_save
= 0;
4573 /* lmf_offset is the offset of the LMF from our stack pointer. */
4574 guint32 lmf_offset
= cfg
->arch
.lmf_offset
;
4577 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
))
4581 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
4583 sig
= mono_method_signature (method
);
4584 cfg
->code_size
= 768 + sig
->param_count
* 20;
4585 code
= cfg
->native_code
= g_malloc (cfg
->code_size
);
4588 #if _MIPS_SIM == _ABIO32
4589 cfg
->arch
.tracing_offset
= cfg
->stack_offset
;
4590 #elif _MIPS_SIM == _ABIN32
4591 /* no stack slots by default for argument regs, reserve a special block */
4592 cfg
->arch
.tracing_offset
= cfg
->stack_offset
;
4593 cfg
->stack_offset
+= 8 * SIZEOF_REGISTER
;
4597 /* adjust stackframe assignments for spillvars if needed */
4598 mips_adjust_stackframe (cfg
);
4600 /* stack_offset should not be changed here. */
4601 alloc_size
= cfg
->stack_offset
;
4602 cfg
->stack_usage
= alloc_size
;
4605 iregs_to_save
= MONO_ARCH_CALLEE_SAVED_REGS
;
4607 iregs_to_save
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
4611 fregs_to_save
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
4613 fregs_to_save
= MONO_ARCH_CALLEE_SAVED_FREGS
;
4614 fregs_to_save
|= (fregs_to_save
<< 1);
4618 if (mips_is_imm16 (-alloc_size
)) {
4619 mips_addiu (code
, mips_sp
, mips_sp
, -alloc_size
);
4621 mips_load_const (code
, mips_at
, -alloc_size
);
4622 mips_addu (code
, mips_sp
, mips_sp
, mips_at
);
4626 if ((cfg
->flags
& MONO_CFG_HAS_CALLS
) || ALWAYS_SAVE_RA
)
4627 mips_sw (code
, mips_ra
, mips_sp
, alloc_size
+ MIPS_RET_ADDR_OFFSET
);
4629 /* XXX - optimize this later to not save all regs if LMF constructed */
4631 if (iregs_to_save
) {
4632 /* save used registers in own stack frame (at pos) */
4633 pos
= cfg
->arch
.iregs_offset
;
4634 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
4635 if (iregs_to_save
& (1 << i
)) {
4636 g_assert (pos
< cfg
->stack_usage
- sizeof(gpointer
));
4637 MIPS_SW (code
, i
, mips_sp
, pos
);
4638 pos
+= SIZEOF_REGISTER
;
4643 if (method
->save_lmf
) {
4644 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
4645 MIPS_SW (code
, i
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, iregs
[i
]));
4651 /* Save float registers */
4652 if (fregs_to_save
) {
4653 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
4654 if (fregs_to_save
& (1 << i
)) {
4655 g_assert (pos
< cfg
->stack_usage
- MIPS_STACK_ALIGNMENT
);
4656 mips_swc1 (code
, i
, mips_sp
, pos
);
4657 pos
+= sizeof (gulong
);
4662 if (method
->save_lmf
) {
4663 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
4664 mips_swc1 (code
, i
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, fregs
[i
]));
4669 if (cfg
->frame_reg
!= mips_sp
) {
4670 MIPS_MOVE (code
, cfg
->frame_reg
, mips_sp
);
4672 if (method
->save_lmf
)
4673 MIPS_SW (code
, cfg
->frame_reg
, mips_sp
,
4674 lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, iregs
[cfg
->frame_reg
]));
4678 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
4679 * to the t* registers, which would be clobbered by the instrumentation calls.
4682 code
= mono_arch_instrument_prolog (cfg
, mono_trace_enter_method
, code
, TRUE
);
4686 /* load arguments allocated to register from the stack */
4689 cinfo
= calculate_sizes (sig
, sig
->pinvoke
);
4691 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
4692 ArgInfo
*ainfo
= &cinfo
->ret
;
4693 inst
= cfg
->vret_addr
;
4694 if (inst
->opcode
== OP_REGVAR
)
4695 MIPS_MOVE (code
, inst
->dreg
, ainfo
->reg
);
4696 else if (mips_is_imm16 (inst
->inst_offset
)) {
4697 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4699 mips_load_const (code
, mips_at
, inst
->inst_offset
);
4700 mips_addu (code
, mips_at
, mips_at
, inst
->inst_basereg
);
4701 mips_sw (code
, ainfo
->reg
, mips_at
, 0);
4704 /* Keep this in sync with emit_load_volatile_arguments */
4705 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4706 ArgInfo
*ainfo
= cinfo
->args
+ i
;
4707 inst
= cfg
->args
[pos
];
4709 if (cfg
->verbose_level
> 2)
4710 g_print ("Saving argument %d (type: %d)\n", i
, ainfo
->regtype
);
4711 if (inst
->opcode
== OP_REGVAR
) {
4712 /* Argument ends up in a register */
4713 if (ainfo
->regtype
== RegTypeGeneral
)
4714 MIPS_MOVE (code
, inst
->dreg
, ainfo
->reg
);
4715 else if (ainfo
->regtype
== RegTypeFP
) {
4716 g_assert_not_reached();
4718 ppc_fmr (code
, inst
->dreg
, ainfo
->reg
);
4721 else if (ainfo
->regtype
== RegTypeBase
) {
4722 mips_lw (code
, inst
->dreg
, mips_sp
, cfg
->stack_usage
+ ainfo
->offset
);
4724 g_assert_not_reached ();
4726 if (cfg
->verbose_level
> 2)
4727 g_print ("Argument %d assigned to register %s\n", pos
, mono_arch_regname (inst
->dreg
));
4729 /* Argument ends up on the stack */
4730 if (ainfo
->regtype
== RegTypeGeneral
) {
4731 /* Incoming parameters should be above this frame */
4732 if (cfg
->verbose_level
> 2)
4733 g_print ("stack slot at %d of %d\n", inst
->inst_offset
, alloc_size
);
4734 /* g_assert (inst->inst_offset >= alloc_size); */
4735 g_assert (mips_is_imm16 (inst
->inst_offset
));
4736 switch (ainfo
->size
) {
4738 mips_sb (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4741 mips_sh (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4745 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4748 #if (SIZEOF_REGISTER == 4)
4749 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4750 mips_sw (code
, ainfo
->reg
+ 1, inst
->inst_basereg
, inst
->inst_offset
+ 4);
4751 #elif (SIZEOF_REGISTER == 8)
4752 mips_sd (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4756 g_assert_not_reached ();
4759 } else if (ainfo
->regtype
== RegTypeBase
) {
4761 * Argument comes in on the stack, and ends up on the stack
4762 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4763 * 8 and 16 bit quantities. Shorten them in place.
4765 g_assert (mips_is_imm16 (inst
->inst_offset
));
4766 switch (ainfo
->size
) {
4768 mips_lw (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4769 mips_sb (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4772 mips_lw (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4773 mips_sh (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4780 g_assert_not_reached ();
4782 } else if (ainfo
->regtype
== RegTypeFP
) {
4783 g_assert (mips_is_imm16 (inst
->inst_offset
));
4784 if (ainfo
->size
== 8) {
4785 #if _MIPS_SIM == _ABIO32
4786 mips_swc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+4);
4787 mips_swc1 (code
, ainfo
->reg
+1, inst
->inst_basereg
, inst
->inst_offset
);
4788 #elif _MIPS_SIM == _ABIN32
4789 mips_sdc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4792 else if (ainfo
->size
== 4)
4793 mips_swc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4795 g_assert_not_reached ();
4796 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
4798 int doffset
= inst
->inst_offset
;
4800 g_assert (mips_is_imm16 (inst
->inst_offset
));
4801 g_assert (mips_is_imm16 (inst
->inst_offset
+ ainfo
->size
* sizeof (gpointer
)));
4802 /* Push the argument registers into their stack slots */
4803 for (i
= 0; i
< ainfo
->size
; ++i
) {
4804 MIPS_SW (code
, ainfo
->reg
+ i
, inst
->inst_basereg
, doffset
);
4805 doffset
+= SIZEOF_REGISTER
;
4807 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
4808 g_assert (mips_is_imm16 (inst
->inst_offset
));
4809 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4810 code
= emit_memcpy (code
, ainfo
->vtsize
* sizeof (gpointer
), inst
->inst_basereg
, inst
->inst_offset
, ainfo
->reg
, 0);
4812 g_assert_not_reached ();
4817 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
4818 mips_load_const (code
, mips_a0
, cfg
->domain
);
4819 mips_load_const (code
, mips_t9
, (gpointer
)mono_jit_thread_attach
);
4820 mips_jalr (code
, mips_t9
, mips_ra
);
4825 if (method
->save_lmf
) {
4826 mips_load_const (code
, mips_at
, MIPS_LMF_MAGIC1
);
4827 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, magic
));
4829 if (lmf_pthread_key
!= -1) {
4830 g_assert_not_reached();
4832 emit_tls_access (code
, mips_temp
, lmf_pthread_key
);
4834 if (G_STRUCT_OFFSET (MonoJitTlsData
, lmf
))
4835 mips_addiu (code
, mips_a0
, mips_temp
, G_STRUCT_OFFSET (MonoJitTlsData
, lmf
));
4838 mips_addiu (code
, mips_a0
, mips_sp
, lmf_offset
);
4839 mips_load_const (code
, mips_t9
, (gpointer
)mono_trace_lmf_prolog
);
4840 mips_jalr (code
, mips_t9
, mips_ra
);
4843 /* This can/will clobber the a0-a3 registers */
4844 mips_load_const (code
, mips_t9
, (gpointer
)mono_get_lmf_addr
);
4845 mips_jalr (code
, mips_t9
, mips_ra
);
4849 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4850 mips_sw (code
, mips_v0
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
4851 /* new_lmf->previous_lmf = *lmf_addr */
4852 mips_lw (code
, mips_at
, mips_v0
, 0);
4853 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
4854 /* *(lmf_addr) = sp + lmf_offset */
4855 mips_addiu (code
, mips_at
, mips_sp
, lmf_offset
);
4856 mips_sw (code
, mips_at
, mips_v0
, 0);
4858 /* save method info */
4859 mips_load_const (code
, mips_at
, method
);
4860 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, method
));
4861 MIPS_SW (code
, mips_sp
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, ebp
));
4863 /* save the current IP */
4864 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_IP
, NULL
);
4865 mips_load_const (code
, mips_at
, 0x01010101);
4866 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, eip
));
4870 cfg
->code_len
= code
- cfg
->native_code
;
4871 g_assert (cfg
->code_len
< cfg
->code_size
);
4886 mono_arch_instrument_epilog_full (MonoCompile
*cfg
, void *func
, void *p
, gboolean enable_arguments
, gboolean preserve_argument_registers
)
4889 int save_mode
= SAVE_NONE
;
4891 MonoMethod
*method
= cfg
->method
;
4892 int rtype
= mono_type_get_underlying_type (mono_method_signature (method
)->ret
)->type
;
4893 int save_offset
= MIPS_STACK_PARAM_OFFSET
;
4895 g_assert ((save_offset
& (MIPS_STACK_ALIGNMENT
-1)) == 0);
4897 offset
= code
- cfg
->native_code
;
4898 /* we need about 16 instructions */
4899 if (offset
> (cfg
->code_size
- 16 * 4)) {
4900 cfg
->code_size
*= 2;
4901 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
4902 code
= cfg
->native_code
+ offset
;
4907 case MONO_TYPE_VOID
:
4908 /* special case string .ctor icall */
4909 if (strcmp (".ctor", method
->name
) && method
->klass
== mono_defaults
.string_class
)
4910 save_mode
= SAVE_ONE
;
4912 save_mode
= SAVE_NONE
;
4916 save_mode
= SAVE_FP
;
4918 case MONO_TYPE_VALUETYPE
:
4919 save_mode
= SAVE_STRUCT
;
4923 #if SIZEOF_REGISTER == 4
4924 save_mode
= SAVE_TWO
;
4925 #elif SIZEOF_REGISTER == 8
4926 save_mode
= SAVE_ONE
;
4930 save_mode
= SAVE_ONE
;
4934 mips_addiu (code
, mips_sp
, mips_sp
, -32);
4935 switch (save_mode
) {
4937 mips_sw (code
, mips_v0
, mips_sp
, save_offset
);
4938 mips_sw (code
, mips_v1
, mips_sp
, save_offset
+ SIZEOF_REGISTER
);
4939 if (enable_arguments
) {
4940 MIPS_MOVE (code
, mips_a1
, mips_v0
);
4941 MIPS_MOVE (code
, mips_a2
, mips_v1
);
4945 MIPS_SW (code
, mips_v0
, mips_sp
, save_offset
);
4946 if (enable_arguments
) {
4947 MIPS_MOVE (code
, mips_a1
, mips_v0
);
4951 mips_sdc1 (code
, mips_f0
, mips_sp
, save_offset
);
4952 mips_ldc1 (code
, mips_f12
, mips_sp
, save_offset
);
4953 mips_lw (code
, mips_a0
, mips_sp
, save_offset
);
4954 mips_lw (code
, mips_a1
, mips_sp
, save_offset
+ SIZEOF_REGISTER
);
4961 mips_load_const (code
, mips_a0
, cfg
->method
);
4962 mips_load_const (code
, mips_t9
, func
);
4963 mips_jalr (code
, mips_t9
, mips_ra
);
4966 switch (save_mode
) {
4968 mips_lw (code
, mips_v0
, mips_sp
, save_offset
);
4969 mips_lw (code
, mips_v1
, mips_sp
, save_offset
+ SIZEOF_REGISTER
);
4972 MIPS_LW (code
, mips_v0
, mips_sp
, save_offset
);
4975 mips_ldc1 (code
, mips_f0
, mips_sp
, save_offset
);
4982 mips_addiu (code
, mips_sp
, mips_sp
, 32);
4989 mono_arch_emit_epilog_sub (MonoCompile
*cfg
, guint8
*code
)
4991 MonoMethod
*method
= cfg
->method
;
4993 int max_epilog_size
= 16 + 20*4;
4994 guint32 iregs_to_restore
;
4996 guint32 fregs_to_restore
;
5000 if (cfg
->method
->save_lmf
)
5001 max_epilog_size
+= 128;
5004 if (mono_jit_trace_calls
!= NULL
)
5005 max_epilog_size
+= 50;
5007 if (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
)
5008 max_epilog_size
+= 50;
5011 pos
= code
- cfg
->native_code
;
5012 while (cfg
->code_len
+ max_epilog_size
> (cfg
->code_size
- 16)) {
5013 cfg
->code_size
*= 2;
5014 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
5015 mono_jit_stats
.code_reallocs
++;
5019 * Keep in sync with OP_JMP
5022 code
= cfg
->native_code
+ pos
;
5024 code
= cfg
->native_code
+ cfg
->code_len
;
5026 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
)) {
5027 code
= mono_arch_instrument_epilog (cfg
, mono_trace_leave_method
, code
, TRUE
);
5029 pos
= cfg
->arch
.iregs_offset
;
5030 if (cfg
->frame_reg
!= mips_sp
) {
5031 MIPS_MOVE (code
, mips_sp
, cfg
->frame_reg
);
5034 iregs_to_restore
= MONO_ARCH_CALLEE_SAVED_REGS
;
5036 iregs_to_restore
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
5038 if (iregs_to_restore
) {
5039 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
5040 if (iregs_to_restore
& (1 << i
)) {
5041 MIPS_LW (code
, i
, mips_sp
, pos
);
5042 pos
+= SIZEOF_REGISTER
;
5049 fregs_to_restore
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
5051 fregs_to_restore
= MONO_ARCH_CALLEE_SAVED_FREGS
;
5052 fregs_to_restore
|= (fregs_to_restore
<< 1);
5054 if (fregs_to_restore
) {
5055 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
5056 if (fregs_to_restore
& (1 << i
)) {
5057 g_assert (pos
< cfg
->stack_usage
- MIPS_STACK_ALIGNMENT
);
5058 mips_lwc1 (code
, i
, mips_sp
, pos
);
5065 /* Unlink the LMF if necessary */
5066 if (method
->save_lmf
) {
5067 int lmf_offset
= cfg
->arch
.lmf_offset
;
5069 /* t0 = current_lmf->previous_lmf */
5070 mips_lw (code
, mips_temp
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
5072 mips_lw (code
, mips_t1
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
5073 /* (*lmf_addr) = previous_lmf */
5074 mips_sw (code
, mips_temp
, mips_t1
, 0);
5078 /* Restore the fp */
5079 mips_lw (code
, mips_fp
, mips_sp
, cfg
->stack_usage
+ MIPS_FP_ADDR_OFFSET
);
5081 /* Correct the stack pointer */
5082 if ((cfg
->flags
& MONO_CFG_HAS_CALLS
) || ALWAYS_SAVE_RA
)
5083 mips_lw (code
, mips_ra
, mips_sp
, cfg
->stack_usage
+ MIPS_RET_ADDR_OFFSET
);
5084 mips_addiu (code
, mips_sp
, mips_sp
, cfg
->stack_usage
);
5086 /* Caller will emit either return or tail-call sequence */
5088 cfg
->code_len
= code
- cfg
->native_code
;
5090 g_assert (cfg
->code_len
< cfg
->code_size
);
5095 mono_arch_emit_epilog (MonoCompile
*cfg
)
5099 code
= mono_arch_emit_epilog_sub (cfg
, NULL
);
5101 mips_jr (code
, mips_ra
);
5104 cfg
->code_len
= code
- cfg
->native_code
;
5106 g_assert (cfg
->code_len
< cfg
->code_size
);
5109 /* remove once throw_exception_by_name is eliminated */
5112 exception_id_by_name (const char *name
)
5114 if (strcmp (name
, "IndexOutOfRangeException") == 0)
5115 return MONO_EXC_INDEX_OUT_OF_RANGE
;
5116 if (strcmp (name
, "OverflowException") == 0)
5117 return MONO_EXC_OVERFLOW
;
5118 if (strcmp (name
, "ArithmeticException") == 0)
5119 return MONO_EXC_ARITHMETIC
;
5120 if (strcmp (name
, "DivideByZeroException") == 0)
5121 return MONO_EXC_DIVIDE_BY_ZERO
;
5122 if (strcmp (name
, "InvalidCastException") == 0)
5123 return MONO_EXC_INVALID_CAST
;
5124 if (strcmp (name
, "NullReferenceException") == 0)
5125 return MONO_EXC_NULL_REF
;
5126 if (strcmp (name
, "ArrayTypeMismatchException") == 0)
5127 return MONO_EXC_ARRAY_TYPE_MISMATCH
;
5128 g_error ("Unknown intrinsic exception %s\n", name
);
5134 mono_arch_emit_exceptions (MonoCompile
*cfg
)
5137 MonoJumpInfo
*patch_info
;
5140 const guint8
* exc_throw_pos
[MONO_EXC_INTRINS_NUM
] = {NULL
};
5141 guint8 exc_throw_found
[MONO_EXC_INTRINS_NUM
] = {0};
5142 int max_epilog_size
= 50;
5144 /* count the number of exception infos */
5147 * make sure we have enough space for exceptions
5148 * 24 is the simulated call to throw_exception_by_name
5150 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5152 if (patch_info
->type
== MONO_PATCH_INFO_EXC
) {
5153 i
= exception_id_by_name (patch_info
->data
.target
);
5154 g_assert (i
< MONO_EXC_INTRINS_NUM
);
5155 if (!exc_throw_found
[i
]) {
5156 max_epilog_size
+= 12;
5157 exc_throw_found
[i
] = TRUE
;
5163 while (cfg
->code_len
+ max_epilog_size
> (cfg
->code_size
- 16)) {
5164 cfg
->code_size
*= 2;
5165 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
5166 mono_jit_stats
.code_reallocs
++;
5169 code
= cfg
->native_code
+ cfg
->code_len
;
5171 /* add code to raise exceptions */
5172 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5173 switch (patch_info
->type
) {
5174 case MONO_PATCH_INFO_EXC
: {
5176 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5178 i
= exception_id_by_name (patch_info
->data
.target
);
5179 g_assert (i
>= 0 && i
< MONO_EXC_INTRINS_NUM
);
5180 if (!exc_throw_pos
[i
]) {
5183 exc_throw_pos
[i
] = code
;
5184 //g_print ("exc: writing stub at %p\n", code);
5185 mips_load_const (code
, mips_a0
, patch_info
->data
.target
);
5186 addr
= (guint32
) mono_arch_get_throw_exception_by_name ();
5187 mips_load_const (code
, mips_t9
, addr
);
5188 mips_jr (code
, mips_t9
);
5191 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5193 /* Turn into a Relative patch, pointing at code stub */
5194 patch_info
->type
= MONO_PATCH_INFO_METHOD_REL
;
5195 patch_info
->data
.offset
= exc_throw_pos
[i
] - cfg
->native_code
;
5197 g_assert_not_reached();
5207 cfg
->code_len
= code
- cfg
->native_code
;
5209 g_assert (cfg
->code_len
< cfg
->code_size
);
5214 * Thread local storage support
5217 setup_tls_access (void)
5220 //guint32 *ins, *code;
5222 if (tls_mode
== TLS_MODE_FAILED
)
5225 if (g_getenv ("MONO_NO_TLS")) {
5226 tls_mode
= TLS_MODE_FAILED
;
5230 if (tls_mode
== TLS_MODE_DETECT
) {
5232 tls_mode
= TLS_MODE_FAILED
;
5236 ins
= (guint32
*)pthread_getspecific
;
5237 /* uncond branch to the real method */
5238 if ((*ins
>> 26) == 18) {
5240 val
= (*ins
& ~3) << 6;
5244 ins
= (guint32
*)val
;
5246 ins
= (guint32
*) ((char*)ins
+ val
);
5249 code
= &cmplwi_1023
;
5250 ppc_cmpli (code
, 0, 0, ppc_r3
, 1023);
5252 ppc_li (code
, ppc_r4
, 0x48);
5255 if (*ins
== cmplwi_1023
) {
5256 int found_lwz_284
= 0;
5257 for (ptk
= 0; ptk
< 20; ++ptk
) {
5259 if (!*ins
|| *ins
== blr_ins
)
5261 if ((guint16
)*ins
== 284 && (*ins
>> 26) == 32) {
5266 if (!found_lwz_284
) {
5267 tls_mode
= TLS_MODE_FAILED
;
5270 tls_mode
= TLS_MODE_LTHREADS
;
5271 } else if (*ins
== li_0x48
) {
5273 /* uncond branch to the real method */
5274 if ((*ins
>> 26) == 18) {
5276 val
= (*ins
& ~3) << 6;
5280 ins
= (guint32
*)val
;
5282 ins
= (guint32
*) ((char*)ins
+ val
);
5285 ppc_li (code
, ppc_r0
, 0x7FF2);
5286 if (ins
[1] == val
) {
5287 /* Darwin on G4, implement */
5288 tls_mode
= TLS_MODE_FAILED
;
5292 ppc_mfspr (code
, ppc_r3
, 104);
5293 if (ins
[1] != val
) {
5294 tls_mode
= TLS_MODE_FAILED
;
5297 tls_mode
= TLS_MODE_DARWIN_G5
;
5300 tls_mode
= TLS_MODE_FAILED
;
5304 tls_mode
= TLS_MODE_FAILED
;
5309 if (monodomain_key
== -1) {
5310 ptk
= mono_domain_get_tls_key ();
5312 ptk
= mono_pthread_key_for_tls (ptk
);
5314 monodomain_key
= ptk
;
5318 if (lmf_pthread_key
== -1) {
5319 ptk
= mono_pthread_key_for_tls (mono_jit_tls_id
);
5321 /*g_print ("MonoLMF at: %d\n", ptk);*/
5322 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5323 init_tls_failed = 1;
5326 lmf_pthread_key
= ptk
;
5329 if (monothread_key
== -1) {
5330 ptk
= mono_thread_get_tls_key ();
5332 ptk
= mono_pthread_key_for_tls (ptk
);
5334 monothread_key
= ptk
;
5335 /*g_print ("thread inited: %d\n", ptk);*/
5338 /*g_print ("thread not inited yet %d\n", ptk);*/
5344 mono_arch_setup_jit_tls_data (MonoJitTlsData
*tls
)
5346 setup_tls_access ();
5350 mono_arch_free_jit_tls_data (MonoJitTlsData
*tls
)
5355 mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
, int this_reg
, int this_type
, int vt_reg
)
5357 int this_dreg
= mips_a0
;
5360 this_dreg
= mips_a1
;
5362 /* add the this argument */
5363 if (this_reg
!= -1) {
5365 MONO_INST_NEW (cfg
, this, OP_MOVE
);
5366 this->type
= this_type
;
5367 this->sreg1
= this_reg
;
5368 this->dreg
= mono_alloc_ireg (cfg
);
5369 mono_bblock_add_inst (cfg
->cbb
, this);
5370 mono_call_inst_add_outarg_reg (cfg
, inst
, this->dreg
, this_dreg
, FALSE
);
5375 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
5376 vtarg
->type
= STACK_MP
;
5377 vtarg
->sreg1
= vt_reg
;
5378 vtarg
->dreg
= mono_alloc_ireg (cfg
);
5379 mono_bblock_add_inst (cfg
->cbb
, vtarg
);
5380 mono_call_inst_add_outarg_reg (cfg
, inst
, vtarg
->dreg
, mips_a0
, FALSE
);
5385 mono_arch_get_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
5387 MonoInst
*ins
= NULL
;
5393 mono_arch_emit_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
5399 mono_arch_print_tree (MonoInst
*tree
, int arity
)
5404 MonoInst
* mono_arch_get_domain_intrinsic (MonoCompile
* cfg
)
5408 setup_tls_access ();
5409 if (monodomain_key
== -1)
5412 MONO_INST_NEW (cfg
, ins
, OP_TLS_GET
);
5413 ins
->inst_offset
= monodomain_key
;
5418 mono_arch_context_get_int_reg (MonoContext
*ctx
, int reg
)
5420 /* FIXME: implement */
5421 g_assert_not_reached ();
5424 #ifdef MONO_ARCH_HAVE_IMT
5428 #define JUMP_IMM_SIZE 12
5429 #define JUMP_IMM32_SIZE 16
5430 #define ENABLE_WRONG_METHOD_CHECK 0
5433 * LOCKING: called with the domain lock held
5436 mono_arch_build_imt_thunk (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
,
5437 gpointer fail_tramp
)
5443 guint8
*code
, *start
;
5445 for (i
= 0; i
< count
; ++i
) {
5446 MonoIMTCheckItem
*item
= imt_entries
[i
];
5447 if (item
->is_equals
) {
5448 if (item
->check_target_idx
) {
5449 if (!item
->compare_done
)
5450 item
->chunk_size
+= CMP_SIZE
;
5452 item
->chunk_size
+= BR_SIZE
+ JUMP_IMM32_SIZE
;
5454 item
->chunk_size
+= BR_SIZE
+ JUMP_IMM_SIZE
;
5457 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
+ JUMP_IMM32_SIZE
* 2;
5459 item
->chunk_size
+= JUMP_IMM_SIZE
;
5460 #if ENABLE_WRONG_METHOD_CHECK
5461 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
+ 4;
5466 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
;
5467 imt_entries
[item
->check_target_idx
]->compare_done
= TRUE
;
5469 size
+= item
->chunk_size
;
5472 code
= mono_method_alloc_generic_virtual_thunk (domain
, size
);
5474 /* the initial load of the vtable address */
5476 code
= mono_domain_code_reserve (domain
, size
);
5480 ppc_load (code
, ppc_r11
, (guint32
)(& (vtable
->vtable
[0])));
5481 for (i
= 0; i
< count
; ++i
) {
5482 MonoIMTCheckItem
*item
= imt_entries
[i
];
5483 item
->code_target
= code
;
5484 if (item
->is_equals
) {
5485 if (item
->check_target_idx
) {
5486 if (!item
->compare_done
) {
5487 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5488 ppc_cmpl (code
, 0, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5490 item
->jmp_code
= code
;
5491 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5493 ppc_load (code
, ppc_r0
, item
->value
.target_code
);
5495 ppc_lwz (code
, ppc_r0
, (sizeof (gpointer
) * item
->value
.vtable_slot
), ppc_r11
);
5496 ppc_mtctr (code
, ppc_r0
);
5497 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5500 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5501 ppc_cmpl (code
, 0, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5502 item
->jmp_code
= code
;
5503 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5504 ppc_load (code
, ppc_r0
, item
->value
.target_code
);
5505 ppc_mtctr (code
, ppc_r0
);
5506 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5507 ppc_patch (item
->jmp_code
, code
);
5508 ppc_load (code
, ppc_r0
, fail_tramp
);
5509 ppc_mtctr (code
, ppc_r0
);
5510 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5511 item
->jmp_code
= NULL
;
5513 /* enable the commented code to assert on wrong method */
5514 #if ENABLE_WRONG_METHOD_CHECK
5515 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5516 ppc_cmpl (code
, 0, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5517 item
->jmp_code
= code
;
5518 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5520 ppc_lwz (code
, ppc_r0
, (sizeof (gpointer
) * item
->value
.vtable_slot
), ppc_r11
);
5521 ppc_mtctr (code
, ppc_r0
);
5522 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5523 #if ENABLE_WRONG_METHOD_CHECK
5524 ppc_patch (item
->jmp_code
, code
);
5526 item
->jmp_code
= NULL
;
5531 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5532 ppc_cmpl (code
, 0, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5533 item
->jmp_code
= code
;
5534 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_LT
, 0);
5537 /* patch the branches to get to the target items */
5538 for (i
= 0; i
< count
; ++i
) {
5539 MonoIMTCheckItem
*item
= imt_entries
[i
];
5540 if (item
->jmp_code
) {
5541 if (item
->check_target_idx
) {
5542 ppc_patch (item
->jmp_code
, imt_entries
[item
->check_target_idx
]->code_target
);
5548 mono_stats
.imt_thunks_size
+= code
- start
;
5549 g_assert (code
- start
<= size
);
5550 mono_arch_flush_icache (start
, size
);
5556 mono_arch_find_imt_method (mgreg_t
*regs
, guint8
*code
)
5558 return (MonoMethod
*) regs
[MONO_ARCH_IMT_REG
];
5563 mono_arch_find_static_call_vtable (mgreg_t
*regs
, guint8
*code
)
5566 return (MonoVTable
*) regs
[MONO_ARCH_RGCTX_REG
];