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
)
189 mips_load_const (code
, mips_a0
, name
);
190 addr
= (guint32
) mono_arch_get_throw_exception_by_name ();
191 mips_load_const (code
, mips_t9
, addr
);
192 mips_jalr (code
, mips_t9
, mips_ra
);
200 mips_emit_load_const(guint8
*code
, int dreg
, mgreg_t v
)
202 if (mips_is_imm16 (v
))
203 mips_addiu (code
, dreg
, mips_zero
, ((guint32
)v
) & 0xffff);
205 #ifdef SIZEOF_REGISTER == 8
207 /* v is not a sign-extended 32-bit value */
208 mips_lui (code
, dreg
, mips_zero
, (guint32
)((v
>> (32+16)) & 0xffff));
209 mips_ori (code
, dreg
, dreg
, (guint32
)((v
>> (32)) & 0xffff));
210 mips_dsll (code
, dreg
, dreg
, 16);
211 mips_ori (code
, dreg
, dreg
, (guint32
)((v
>> (16)) & 0xffff));
212 mips_dsll (code
, dreg
, dreg
, 16);
213 mips_ori (code
, dreg
, dreg
, (guint32
)(v
& 0xffff));
217 if (((guint32
)v
) & (1 << 15)) {
218 mips_lui (code
, dreg
, mips_zero
, (((guint32
)v
)>>16)+1);
221 mips_lui (code
, dreg
, mips_zero
, (((guint32
)v
)>>16));
223 if (((guint32
)v
) & 0xffff)
224 mips_addiu (code
, dreg
, dreg
, ((guint32
)v
) & 0xffff);
230 mips_emit_cond_branch (MonoCompile
*cfg
, guint8
*code
, int op
, MonoInst
*ins
)
238 /* Invert test and emit branch around jump */
241 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, br_offset
);
245 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, br_offset
);
249 mips_bltz (code
, ins
->sreg1
, br_offset
);
253 mips_blez (code
, ins
->sreg1
, br_offset
);
257 mips_bgtz (code
, ins
->sreg1
, br_offset
);
261 mips_bgez (code
, ins
->sreg1
, br_offset
);
265 g_assert_not_reached ();
267 if (ins
->flags
& MONO_INST_BRLABEL
)
268 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
269 MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
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 if (ins
->flags
& MONO_INST_BRLABEL
)
279 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
280 MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
282 mono_add_patch_info (cfg
, code
- cfg
->native_code
,
283 MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
286 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, 0);
290 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, 0);
294 mips_bgez (code
, ins
->sreg1
, 0);
298 mips_bgtz (code
, ins
->sreg1
, 0);
302 mips_blez (code
, ins
->sreg1
, 0);
306 mips_bltz (code
, ins
->sreg1
, 0);
310 g_assert_not_reached ();
316 /* XXX - big-endian dependent? */
318 patch_lui_addiu(guint32
*ip
, guint32 val
)
320 guint16
*__lui_addiu
= (guint16
*)(void *)(ip
);
323 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
324 ip
, ((guint32
*)ip
)[0], ((guint32
*)ip
)[1], val
);
327 if (((guint32
)(val
)) & (1 << 15))
328 __lui_addiu
[MINI_LS_WORD_IDX
] = ((((guint32
)(val
)) >> 16) & 0xffff) + 1;
330 __lui_addiu
[MINI_LS_WORD_IDX
] = (((guint32
)(val
)) >> 16) & 0xffff;
331 __lui_addiu
[MINI_LS_WORD_IDX
+ 2] = ((guint32
)(val
)) & 0xffff;
332 mono_arch_flush_icache ((guint8
*)ip
, 8);
337 mips_patch (guint32
*code
, guint32 target
)
340 guint32 op
= ins
>> 26;
341 guint32 diff
, offset
;
343 g_assert (trap_target
!= target
);
344 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
346 case 0x00: /* jr ra */
347 if (ins
== 0x3e00008)
349 g_assert_not_reached ();
353 g_assert (!(target
& 0x03));
354 g_assert ((target
& 0xfc000000) == (((guint32
)code
) & 0xfc000000));
355 ins
= (ins
& 0xfc000000) | (((target
) >> 2) & 0x03ffffff);
357 mono_arch_flush_icache ((guint8
*)code
, 4);
359 case 0x01: /* BLTZ */
362 case 0x06: /* BLEZ */
363 case 0x07: /* BGTZ */
364 case 0x11: /* bc1t */
365 diff
= target
- (guint32
)(code
+ 1);
366 g_assert (((diff
& 0x0003ffff) == diff
) || ((diff
| 0xfffc0000) == diff
));
367 g_assert (!(diff
& 0x03));
368 offset
= ((gint32
)diff
) >> 2;
369 g_assert (((int)offset
) == ((int)(short)offset
));
370 ins
= (ins
& 0xffff0000) | (offset
& 0x0000ffff);
372 mono_arch_flush_icache ((guint8
*)code
, 4);
374 case 0x0f: /* LUI / ADDIU pair */
375 patch_lui_addiu (code
, target
);
376 mono_arch_flush_icache ((guint8
*)code
, 8);
380 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op
, ins
, code
);
381 g_assert_not_reached ();
387 offsets_from_pthread_key (guint32 key
, int *offset2
)
391 *offset2
= idx2
* sizeof (gpointer
);
392 return 284 + idx1
* sizeof (gpointer
);
397 mono_arch_regname (int reg
) {
398 #if _MIPS_SIM == _ABIO32
399 static const char * rnames
[] = {
400 "zero", "at", "v0", "v1",
401 "a0", "a1", "a2", "a3",
402 "t0", "t1", "t2", "t3",
403 "t4", "t5", "t6", "t7",
404 "s0", "s1", "s2", "s3",
405 "s4", "s5", "s6", "s7",
406 "t8", "t9", "k0", "k1",
407 "gp", "sp", "fp", "ra"
409 #elif _MIPS_SIM == _ABIN32
410 static const char * rnames
[] = {
411 "zero", "at", "v0", "v1",
412 "a0", "a1", "a2", "a3",
413 "a4", "a5", "a6", "a7",
414 "t0", "t1", "t2", "t3",
415 "s0", "s1", "s2", "s3",
416 "s4", "s5", "s6", "s7",
417 "t8", "t9", "k0", "k1",
418 "gp", "sp", "fp", "ra"
421 if (reg
>= 0 && reg
< 32)
427 mono_arch_fregname (int reg
) {
428 static const char * rnames
[] = {
429 "f0", "f1", "f2", "f3",
430 "f4", "f5", "f6", "f7",
431 "f8", "f9", "f10", "f11",
432 "f12", "f13", "f14", "f15",
433 "f16", "f17", "f18", "f19",
434 "f20", "f21", "f22", "f23",
435 "f24", "f25", "f26", "f27",
436 "f28", "f29", "f30", "f31"
438 if (reg
>= 0 && reg
< 32)
443 /* this function overwrites at */
445 emit_memcpy (guint8
*code
, int size
, int dreg
, int doffset
, int sreg
, int soffset
)
447 /* XXX write a loop, not an unrolled loop */
449 mips_lw (code
, mips_at
, sreg
, soffset
);
450 mips_sw (code
, mips_at
, dreg
, doffset
);
459 * mono_arch_get_argument_info:
460 * @csig: a method signature
461 * @param_count: the number of parameters to consider
462 * @arg_info: an array to store the result infos
464 * Gathers information on parameters such as size, alignment and
465 * padding. arg_info should be large enought to hold param_count + 1 entries.
467 * Returns the size of the activation frame.
470 mono_arch_get_argument_info (MonoMethodSignature
*csig
, int param_count
, MonoJitArgumentInfo
*arg_info
)
472 int k
, frame_size
= 0;
473 guint32 size
, align
, pad
;
476 if (MONO_TYPE_ISSTRUCT (csig
->ret
)) {
477 frame_size
+= sizeof (gpointer
);
481 arg_info
[0].offset
= offset
;
484 frame_size
+= sizeof (gpointer
);
488 arg_info
[0].size
= frame_size
;
490 for (k
= 0; k
< param_count
; k
++) {
491 size
= mini_type_stack_size_full (NULL
, csig
->params
[k
], &align
, csig
->pinvoke
);
493 /* ignore alignment for now */
496 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
497 arg_info
[k
].pad
= pad
;
499 arg_info
[k
+ 1].pad
= 0;
500 arg_info
[k
+ 1].size
= size
;
502 arg_info
[k
+ 1].offset
= offset
;
506 align
= MONO_ARCH_FRAME_ALIGNMENT
;
507 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
508 arg_info
[k
].pad
= pad
;
515 mono_arch_get_this_arg_from_call (MonoGenericSharingContext
*gsctx
, MonoMethodSignature
*sig
, gssize
*regs
, guint8
*code
)
517 /* FIXME: handle returning a struct */
518 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
519 return (gpointer
)regs
[mips_a1
];
520 return (gpointer
)regs
[mips_a0
];
524 * Initialize the cpu to execute managed code.
527 mono_arch_cpu_init (void)
532 * Initialize architecture specific code.
535 mono_arch_init (void)
537 InitializeCriticalSection (&mini_arch_mutex
);
541 * Cleanup architecture specific code.
544 mono_arch_cleanup (void)
546 DeleteCriticalSection (&mini_arch_mutex
);
550 * This function returns the optimizations supported on this cpu.
553 mono_arch_cpu_optimizazions (guint32
*exclude_mask
)
557 /* no mips-specific optimizations yet */
563 is_regsize_var (MonoType
*t
) {
566 t
= mono_type_get_underlying_type (t
);
570 #if (SIZEOF_REGISTER == 8)
577 case MONO_TYPE_FNPTR
:
579 case MONO_TYPE_OBJECT
:
580 case MONO_TYPE_STRING
:
581 case MONO_TYPE_CLASS
:
582 case MONO_TYPE_SZARRAY
:
583 case MONO_TYPE_ARRAY
:
585 case MONO_TYPE_GENERICINST
:
586 if (!mono_type_generic_inst_is_valuetype (t
))
589 case MONO_TYPE_VALUETYPE
:
596 mono_arch_get_allocatable_int_vars (MonoCompile
*cfg
)
601 for (i
= 0; i
< cfg
->num_varinfo
; i
++) {
602 MonoInst
*ins
= cfg
->varinfo
[i
];
603 MonoMethodVar
*vmv
= MONO_VARINFO (cfg
, i
);
606 if (vmv
->range
.first_use
.abs_pos
>= vmv
->range
.last_use
.abs_pos
)
609 if (ins
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
) || (ins
->opcode
!= OP_LOCAL
&& ins
->opcode
!= OP_ARG
))
612 /* we can only allocate 32 bit values */
613 if (is_regsize_var (ins
->inst_vtype
)) {
614 g_assert (MONO_VARINFO (cfg
, i
)->reg
== -1);
615 g_assert (i
== vmv
->idx
);
616 vars
= mono_varlist_insert_sorted (cfg
, vars
, vmv
, FALSE
);
624 mono_arch_get_global_int_regs (MonoCompile
*cfg
)
628 regs
= g_list_prepend (regs
, (gpointer
)mips_s0
);
629 regs
= g_list_prepend (regs
, (gpointer
)mips_s1
);
630 regs
= g_list_prepend (regs
, (gpointer
)mips_s2
);
631 regs
= g_list_prepend (regs
, (gpointer
)mips_s3
);
632 regs
= g_list_prepend (regs
, (gpointer
)mips_s4
);
633 //regs = g_list_prepend (regs, (gpointer)mips_s5);
634 regs
= g_list_prepend (regs
, (gpointer
)mips_s6
);
635 regs
= g_list_prepend (regs
, (gpointer
)mips_s7
);
641 * mono_arch_regalloc_cost:
643 * Return the cost, in number of memory references, of the action of
644 * allocating the variable VMV into a register during global register
648 mono_arch_regalloc_cost (MonoCompile
*cfg
, MonoMethodVar
*vmv
)
655 args_onto_stack (CallInfo
*info
)
657 g_assert (!info
->on_stack
);
658 g_assert (info
->stack_size
<= MIPS_STACK_PARAM_OFFSET
);
659 info
->on_stack
= TRUE
;
660 info
->stack_size
= MIPS_STACK_PARAM_OFFSET
;
663 #if _MIPS_SIM == _ABIO32
665 * O32 calling convention version
669 add_int32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
670 /* First, see if we need to drop onto the stack */
671 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
672 args_onto_stack (info
);
674 /* Now, place the argument */
675 if (info
->on_stack
) {
676 ainfo
->regtype
= RegTypeBase
;
677 ainfo
->reg
= mips_sp
; /* in the caller */
678 ainfo
->offset
= info
->stack_size
;
681 ainfo
->regtype
= RegTypeGeneral
;
682 ainfo
->reg
= info
->gr
;
684 info
->gr_passed
= TRUE
;
686 info
->stack_size
+= 4;
690 add_int64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
691 /* First, see if we need to drop onto the stack */
692 if (!info
->on_stack
&& info
->gr
+1 > MIPS_LAST_ARG_REG
)
693 args_onto_stack (info
);
695 /* Now, place the argument */
696 if (info
->on_stack
) {
697 g_assert (info
->stack_size
% 4 == 0);
698 info
->stack_size
+= (info
->stack_size
% 8);
700 ainfo
->regtype
= RegTypeBase
;
701 ainfo
->reg
= mips_sp
; /* in the caller */
702 ainfo
->offset
= info
->stack_size
;
705 // info->gr must be a0 or a2
706 info
->gr
+= (info
->gr
- MIPS_FIRST_ARG_REG
) % 2;
707 g_assert(info
->gr
<= MIPS_LAST_ARG_REG
);
709 ainfo
->regtype
= RegTypeGeneral
;
710 ainfo
->reg
= info
->gr
;
712 info
->gr_passed
= TRUE
;
714 info
->stack_size
+= 8;
718 add_float32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
719 /* First, see if we need to drop onto the stack */
720 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
721 args_onto_stack (info
);
723 /* Now, place the argument */
724 if (info
->on_stack
) {
725 ainfo
->regtype
= RegTypeBase
;
726 ainfo
->reg
= mips_sp
; /* in the caller */
727 ainfo
->offset
= info
->stack_size
;
730 /* Only use FP regs for args if no int args passed yet */
731 if (!info
->gr_passed
&& info
->fr
<= MIPS_LAST_FPARG_REG
) {
732 ainfo
->regtype
= RegTypeFP
;
733 ainfo
->reg
= info
->fr
;
734 /* Even though it's a single-precision float, it takes up two FP regs */
736 /* FP and GP slots do not overlap */
740 /* Passing single-precision float arg in a GP register
741 * such as: func (0, 1.0, 2, 3);
742 * In this case, only one 'gr' register is consumed.
744 ainfo
->regtype
= RegTypeGeneral
;
745 ainfo
->reg
= info
->gr
;
748 info
->gr_passed
= TRUE
;
751 info
->stack_size
+= 4;
755 add_float64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
756 /* First, see if we need to drop onto the stack */
757 if (!info
->on_stack
&& info
->gr
+1 > MIPS_LAST_ARG_REG
)
758 args_onto_stack (info
);
760 /* Now, place the argument */
761 if (info
->on_stack
) {
762 g_assert(info
->stack_size
% 4 == 0);
763 info
->stack_size
+= (info
->stack_size
% 8);
765 ainfo
->regtype
= RegTypeBase
;
766 ainfo
->reg
= mips_sp
; /* in the caller */
767 ainfo
->offset
= info
->stack_size
;
770 /* Only use FP regs for args if no int args passed yet */
771 if (!info
->gr_passed
&& info
->fr
<= MIPS_LAST_FPARG_REG
) {
772 ainfo
->regtype
= RegTypeFP
;
773 ainfo
->reg
= info
->fr
;
775 /* FP and GP slots do not overlap */
779 // info->gr must be a0 or a2
780 info
->gr
+= (info
->gr
- MIPS_FIRST_ARG_REG
) % 2;
781 g_assert(info
->gr
<= MIPS_LAST_ARG_REG
);
783 ainfo
->regtype
= RegTypeGeneral
;
784 ainfo
->reg
= info
->gr
;
786 info
->gr_passed
= TRUE
;
789 info
->stack_size
+= 8;
791 #elif _MIPS_SIM == _ABIN32
793 * N32 calling convention version
797 add_int32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
798 /* First, see if we need to drop onto the stack */
799 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
800 args_onto_stack (info
);
802 /* Now, place the argument */
803 if (info
->on_stack
) {
804 ainfo
->regtype
= RegTypeBase
;
805 ainfo
->reg
= mips_sp
; /* in the caller */
806 ainfo
->offset
= info
->stack_size
;
807 info
->stack_size
+= SIZEOF_REGISTER
;
810 ainfo
->regtype
= RegTypeGeneral
;
811 ainfo
->reg
= info
->gr
;
813 info
->gr_passed
= TRUE
;
818 add_int64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
819 /* First, see if we need to drop onto the stack */
820 if (!info
->on_stack
&& info
->gr
> MIPS_LAST_ARG_REG
)
821 args_onto_stack (info
);
823 /* Now, place the argument */
824 if (info
->on_stack
) {
825 g_assert (info
->stack_size
% 4 == 0);
826 info
->stack_size
+= (info
->stack_size
% 8);
828 ainfo
->regtype
= RegTypeBase
;
829 ainfo
->reg
= mips_sp
; /* in the caller */
830 ainfo
->offset
= info
->stack_size
;
831 info
->stack_size
+= SIZEOF_REGISTER
;
834 g_assert (info
->gr
<= MIPS_LAST_ARG_REG
);
836 ainfo
->regtype
= RegTypeGeneral
;
837 ainfo
->reg
= info
->gr
;
839 info
->gr_passed
= TRUE
;
844 add_float32_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
845 /* First, see if we need to drop onto the stack */
846 if (!info
->on_stack
) {
847 if (info
->gr
> MIPS_LAST_ARG_REG
)
848 args_onto_stack (info
);
849 else if (info
->fr
> MIPS_LAST_FPARG_REG
)
850 args_onto_stack (info
);
853 /* Now, place the argument */
854 if (info
->on_stack
) {
855 ainfo
->regtype
= RegTypeBase
;
856 ainfo
->reg
= mips_sp
; /* in the caller */
857 ainfo
->offset
= info
->stack_size
;
858 info
->stack_size
+= FREG_SIZE
;
861 ainfo
->regtype
= RegTypeFP
;
862 ainfo
->reg
= info
->fr
;
864 /* FP and GP slots do not overlap */
870 add_float64_arg (CallInfo
*info
, ArgInfo
*ainfo
) {
871 /* First, see if we need to drop onto the stack */
872 if (!info
->on_stack
) {
873 if (info
->gr
> MIPS_LAST_ARG_REG
)
874 args_onto_stack (info
);
875 else if (info
->fr
> MIPS_LAST_FPARG_REG
)
876 args_onto_stack (info
);
879 /* Now, place the argument */
880 if (info
->on_stack
) {
881 g_assert(info
->stack_size
% 4 == 0);
882 info
->stack_size
+= (info
->stack_size
% 8);
884 ainfo
->regtype
= RegTypeBase
;
885 ainfo
->reg
= mips_sp
; /* in the caller */
886 ainfo
->offset
= info
->stack_size
;
887 info
->stack_size
+= FREG_SIZE
;
890 ainfo
->regtype
= RegTypeFP
;
891 ainfo
->reg
= info
->fr
;
893 /* FP and GP slots do not overlap */
900 calculate_sizes (MonoMethodSignature
*sig
, gboolean is_pinvoke
)
903 int n
= sig
->hasthis
+ sig
->param_count
;
905 CallInfo
*cinfo
= g_malloc0 (sizeof (CallInfo
) + sizeof (ArgInfo
) * n
);
907 cinfo
->fr
= MIPS_FIRST_FPARG_REG
;
908 cinfo
->gr
= MIPS_FIRST_ARG_REG
;
909 cinfo
->stack_size
= 0;
911 DEBUG(printf("calculate_sizes\n"));
913 /* handle returning a struct */
914 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
915 cinfo
->struct_ret
= cinfo
->gr
;
916 add_int32_arg (cinfo
, &cinfo
->ret
);
921 add_int32_arg (cinfo
, cinfo
->args
+ n
);
924 DEBUG(printf("params: %d\n", sig
->param_count
));
925 for (i
= 0; i
< sig
->param_count
; ++i
) {
926 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
927 /* Prevent implicit arguments and sig_cookie from
928 being passed in registers */
929 args_onto_stack (cinfo
);
930 /* Emit the signature cookie just before the implicit arguments */
931 add_int32_arg (cinfo
, &cinfo
->sig_cookie
);
933 DEBUG(printf("param %d: ", i
));
934 if (sig
->params
[i
]->byref
) {
935 DEBUG(printf("byref\n"));
936 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
940 simpletype
= mono_type_get_underlying_type (sig
->params
[i
])->type
;
941 switch (simpletype
) {
942 case MONO_TYPE_BOOLEAN
:
945 DEBUG(printf("1 byte\n"));
946 cinfo
->args
[n
].size
= 1;
947 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
953 DEBUG(printf("2 bytes\n"));
954 cinfo
->args
[n
].size
= 2;
955 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
960 DEBUG(printf("4 bytes\n"));
961 cinfo
->args
[n
].size
= 4;
962 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
968 case MONO_TYPE_FNPTR
:
969 case MONO_TYPE_CLASS
:
970 case MONO_TYPE_OBJECT
:
971 case MONO_TYPE_STRING
:
972 case MONO_TYPE_SZARRAY
:
973 case MONO_TYPE_ARRAY
:
974 cinfo
->args
[n
].size
= sizeof (gpointer
);
975 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
978 case MONO_TYPE_GENERICINST
:
979 if (!mono_type_generic_inst_is_valuetype (sig
->params
[i
])) {
980 cinfo
->args
[n
].size
= sizeof (gpointer
);
981 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
986 case MONO_TYPE_VALUETYPE
: {
989 int has_offset
= FALSE
;
991 gint size
, alignment
;
994 klass
= mono_class_from_mono_type (sig
->params
[i
]);
996 size
= mono_class_native_size (klass
, NULL
);
998 size
= mono_class_value_size (klass
, NULL
);
999 alignment
= mono_class_min_align (klass
);
1000 #if MIPS_PASS_STRUCTS_BY_VALUE
1001 /* Need to do alignment if struct contains long or double */
1002 if (alignment
> 4) {
1003 if (cinfo
->stack_size
& (alignment
- 1)) {
1004 add_int32_arg (cinfo
, &dummy_arg
);
1006 g_assert (!(cinfo
->stack_size
& (alignment
- 1)));
1010 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1011 mono_class_native_size (sig
->params
[i
]->data
.klass
, NULL
),
1012 cinfo
->stack_size
, alignment
);
1014 nwords
= (size
+ sizeof (gpointer
) -1 ) / sizeof (gpointer
);
1015 g_assert (cinfo
->args
[n
].size
== 0);
1016 g_assert (cinfo
->args
[n
].vtsize
== 0);
1017 for (j
= 0; j
< nwords
; ++j
) {
1019 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1020 if (cinfo
->on_stack
)
1023 add_int32_arg (cinfo
, &dummy_arg
);
1024 if (!has_offset
&& cinfo
->on_stack
) {
1025 cinfo
->args
[n
].offset
= dummy_arg
.offset
;
1029 if (cinfo
->on_stack
)
1030 cinfo
->args
[n
].vtsize
+= 1;
1032 cinfo
->args
[n
].size
+= 1;
1034 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1035 cinfo
->args
[n
].regtype
= RegTypeStructByVal
;
1037 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1038 cinfo
->args
[n
].regtype
= RegTypeStructByAddr
;
1043 case MONO_TYPE_TYPEDBYREF
: {
1044 /* keep in sync or merge with the valuetype case */
1045 #if MIPS_PASS_STRUCTS_BY_VALUE
1047 int size
= sizeof (MonoTypedRef
);
1048 int nwords
= (size
+ sizeof (gpointer
) -1 ) / sizeof (gpointer
);
1049 cinfo
->args
[n
].regtype
= RegTypeStructByVal
;
1050 if (!cinfo
->on_stack
&& cinfo
->gr
<= MIPS_LAST_ARG_REG
) {
1051 int rest
= MIPS_LAST_ARG_REG
- cinfo
->gr
+ 1;
1052 int n_in_regs
= rest
>= nwords
? nwords
: rest
;
1053 cinfo
->args
[n
].size
= n_in_regs
;
1054 cinfo
->args
[n
].vtsize
= nwords
- n_in_regs
;
1055 cinfo
->args
[n
].reg
= cinfo
->gr
;
1056 cinfo
->gr
+= n_in_regs
;
1057 cinfo
->gr_passed
= TRUE
;
1059 cinfo
->args
[n
].size
= 0;
1060 cinfo
->args
[n
].vtsize
= nwords
;
1062 if (cinfo
->args
[n
].vtsize
> 0) {
1063 if (!cinfo
->on_stack
)
1064 args_onto_stack (cinfo
);
1065 g_assert(cinfo
->on_stack
);
1066 cinfo
->args
[n
].offset
= cinfo
->stack_size
;
1067 g_print ("offset for arg %d at %d\n", n
, cinfo
->args
[n
].offset
);
1068 cinfo
->stack_size
+= cinfo
->args
[n
].vtsize
* sizeof (gpointer
);
1072 add_int32_arg (cinfo
, &cinfo
->args
[n
]);
1073 cinfo
->args
[n
].regtype
= RegTypeStructByAddr
;
1080 DEBUG(printf("8 bytes\n"));
1081 cinfo
->args
[n
].size
= 8;
1082 add_int64_arg (cinfo
, &cinfo
->args
[n
]);
1086 DEBUG(printf("R4\n"));
1087 cinfo
->args
[n
].size
= 4;
1088 add_float32_arg (cinfo
, &cinfo
->args
[n
]);
1092 DEBUG(printf("R8\n"));
1093 cinfo
->args
[n
].size
= 8;
1094 add_float64_arg (cinfo
, &cinfo
->args
[n
]);
1098 g_error ("Can't trampoline 0x%x", sig
->params
[i
]->type
);
1103 simpletype
= mono_type_get_underlying_type (sig
->ret
)->type
;
1104 switch (simpletype
) {
1105 case MONO_TYPE_BOOLEAN
:
1110 case MONO_TYPE_CHAR
:
1116 case MONO_TYPE_FNPTR
:
1117 case MONO_TYPE_CLASS
:
1118 case MONO_TYPE_OBJECT
:
1119 case MONO_TYPE_SZARRAY
:
1120 case MONO_TYPE_ARRAY
:
1121 case MONO_TYPE_STRING
:
1122 cinfo
->ret
.reg
= mips_v0
;
1126 cinfo
->ret
.reg
= mips_v0
;
1130 cinfo
->ret
.reg
= mips_f0
;
1131 cinfo
->ret
.regtype
= RegTypeFP
;
1133 case MONO_TYPE_GENERICINST
:
1134 if (!mono_type_generic_inst_is_valuetype (sig
->ret
)) {
1135 cinfo
->ret
.reg
= mips_v0
;
1139 case MONO_TYPE_VALUETYPE
:
1141 case MONO_TYPE_TYPEDBYREF
:
1142 case MONO_TYPE_VOID
:
1145 g_error ("Can't handle as return value 0x%x", sig
->ret
->type
);
1149 /* align stack size to 16 */
1150 cinfo
->stack_size
= (cinfo
->stack_size
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1152 cinfo
->stack_usage
= cinfo
->stack_size
;
1158 * Set var information according to the calling convention. mips version.
1159 * The locals var stuff should most likely be split in another method.
1162 mono_arch_allocate_vars (MonoCompile
*cfg
)
1164 MonoMethodSignature
*sig
;
1165 MonoMethodHeader
*header
;
1167 int i
, offset
, size
, align
, curinst
;
1168 int frame_reg
= mips_sp
;
1169 guint32 iregs_to_save
= 0;
1171 guint32 fregs_to_restore
;
1174 /* spill down, we'll fix it in a separate pass */
1175 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1177 /* allow room for the vararg method args: void* and long/double */
1178 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (cfg
->method
))
1179 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (gpointer
)*8);
1181 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1182 * call convs needs to be handled this way.
1184 if (cfg
->flags
& MONO_CFG_HAS_VARARGS
)
1185 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (gpointer
)*8);
1187 /* gtk-sharp and other broken code will dllimport vararg functions even with
1188 * non-varargs signatures. Since there is little hope people will get this right
1189 * we assume they won't.
1191 if (cfg
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
1192 cfg
->param_area
= MAX (cfg
->param_area
, sizeof (gpointer
)*8);
1194 /* a0-a3 always present */
1195 cfg
->param_area
= MAX (cfg
->param_area
, MIPS_STACK_PARAM_OFFSET
);
1197 header
= mono_method_get_header (cfg
->method
);
1199 sig
= mono_method_signature (cfg
->method
);
1202 * We use the frame register also for any method that has
1203 * exception clauses. This way, when the handlers are called,
1204 * the code will reference local variables using the frame reg instead of
1205 * the stack pointer: if we had to restore the stack pointer, we'd
1206 * corrupt the method frames that are already on the stack (since
1207 * filters get called before stack unwinding happens) when the filter
1208 * code would call any method (this also applies to finally etc.).
1211 if ((cfg
->flags
& MONO_CFG_HAS_ALLOCA
) || header
->num_clauses
|| ALWAYS_USE_FP
)
1212 frame_reg
= mips_fp
;
1213 cfg
->frame_reg
= frame_reg
;
1214 if (frame_reg
!= mips_sp
) {
1215 cfg
->used_int_regs
|= 1 << frame_reg
;
1220 if (!MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1221 /* FIXME: handle long and FP values */
1222 switch (mono_type_get_underlying_type (sig
->ret
)->type
) {
1223 case MONO_TYPE_VOID
:
1227 cfg
->ret
->opcode
= OP_REGVAR
;
1228 cfg
->ret
->inst_c0
= cfg
->ret
->dreg
= mips_f0
;
1231 cfg
->ret
->opcode
= OP_REGVAR
;
1232 cfg
->ret
->inst_c0
= mips_v0
;
1236 /* Space for outgoing parameters, including a0-a3 */
1237 offset
+= cfg
->param_area
;
1239 /* allow room to save the return value (if it's a struct) */
1240 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (cfg
->method
))
1243 if (sig
->call_convention
== MONO_CALL_VARARG
) {
1244 cfg
->sig_cookie
= MIPS_STACK_PARAM_OFFSET
;
1247 /* Now handle the local variables */
1249 curinst
= cfg
->locals_start
;
1250 for (i
= curinst
; i
< cfg
->num_varinfo
; ++i
) {
1251 inst
= cfg
->varinfo
[i
];
1252 if ((inst
->flags
& MONO_INST_IS_DEAD
) || inst
->opcode
== OP_REGVAR
)
1255 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1256 * pinvoke wrappers when they call functions returning structure
1258 if (inst
->backend
.is_pinvoke
&& MONO_TYPE_ISSTRUCT (inst
->inst_vtype
) && inst
->inst_vtype
->type
!= MONO_TYPE_TYPEDBYREF
)
1259 size
= mono_class_native_size (mono_class_from_mono_type (inst
->inst_vtype
), &align
);
1261 size
= mono_type_size (inst
->inst_vtype
, &align
);
1263 offset
+= align
- 1;
1264 offset
&= ~(align
- 1);
1265 inst
->inst_offset
= offset
;
1266 inst
->opcode
= OP_REGOFFSET
;
1267 inst
->inst_basereg
= frame_reg
;
1269 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1272 /* Space for LMF (if needed) */
1274 if (cfg
->method
->save_lmf
) {
1275 /* align the offset to 16 bytes */
1276 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1277 cfg
->arch
.lmf_offset
= offset
;
1278 offset
+= sizeof (MonoLMF
);
1282 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1283 * args or return vals. Extra stack space avoids this in a lot of cases.
1285 offset
+= EXTRA_STACK_SPACE
;
1287 /* Space for saved registers */
1288 cfg
->arch
.iregs_offset
= offset
;
1290 iregs_to_save
= MONO_ARCH_CALLEE_SAVED_REGS
;
1292 iregs_to_save
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
1294 if (iregs_to_save
) {
1295 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
1296 if (iregs_to_save
& (1 << i
)) {
1297 offset
+= SIZEOF_REGISTER
;
1302 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1303 * args or return vals. Extra stack space avoids this in a lot of cases.
1305 offset
+= EXTRA_STACK_SPACE
;
1307 /* saved float registers */
1309 fregs_to_restore
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
1310 if (fregs_to_restore
) {
1311 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
1312 if (fregs_to_restore
& (1 << i
)) {
1313 offset
+= sizeof(double);
1319 #if _MIPS_SIM == _ABIO32
1320 /* Now add space for saving the ra */
1321 offset
+= SIZEOF_VOID_P
;
1324 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1325 cfg
->stack_offset
= offset
;
1326 cfg
->arch
.local_alloc_offset
= cfg
->stack_offset
;
1330 * Now allocate stack slots for the int arg regs (a0 - a3)
1331 * On MIPS o32, these are just above the incoming stack pointer
1332 * Even if the arg has been assigned to a regvar, it gets a stack slot
1335 /* Return struct-by-value results in a hidden first argument */
1336 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1337 cfg
->vret_addr
->opcode
= OP_REGOFFSET
;
1338 cfg
->vret_addr
->inst_c0
= mips_a0
;
1339 cfg
->vret_addr
->inst_offset
= offset
;
1340 cfg
->vret_addr
->inst_basereg
= frame_reg
;
1341 offset
+= SIZEOF_REGISTER
;
1344 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
1345 inst
= cfg
->args
[i
];
1346 if (inst
->opcode
!= OP_REGVAR
) {
1349 if (sig
->hasthis
&& (i
== 0))
1350 arg_type
= &mono_defaults
.object_class
->byval_arg
;
1352 arg_type
= sig
->params
[i
- sig
->hasthis
];
1354 inst
->opcode
= OP_REGOFFSET
;
1355 size
= mono_type_size (arg_type
, &align
);
1357 if (size
< SIZEOF_REGISTER
) {
1358 size
= SIZEOF_REGISTER
;
1359 align
= SIZEOF_REGISTER
;
1361 inst
->inst_basereg
= frame_reg
;
1362 offset
= (offset
+ align
- 1) & ~(align
- 1);
1363 inst
->inst_offset
= offset
;
1365 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
< sig
->sentinelpos
))
1366 cfg
->sig_cookie
+= size
;
1367 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1370 #if _MIPS_SIM == _ABIO32
1371 /* o32: Even a0-a3 get stack slots */
1372 size
= SIZEOF_REGISTER
;
1373 align
= SIZEOF_REGISTER
;
1374 inst
->inst_basereg
= frame_reg
;
1375 offset
= (offset
+ align
- 1) & ~(align
- 1);
1376 inst
->inst_offset
= offset
;
1378 if ((sig
->call_convention
== MONO_CALL_VARARG
) && (i
< sig
->sentinelpos
))
1379 cfg
->sig_cookie
+= size
;
1380 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1384 #if _MIPS_SIM == _ABIN32
1385 /* Now add space for saving the ra */
1386 offset
+= SIZEOF_VOID_P
;
1389 offset
= (offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1390 cfg
->stack_offset
= offset
;
1391 cfg
->arch
.local_alloc_offset
= cfg
->stack_offset
;
1396 mono_arch_create_vars (MonoCompile
*cfg
)
1398 MonoMethodSignature
*sig
;
1400 sig
= mono_method_signature (cfg
->method
);
1402 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1403 cfg
->vret_addr
= mono_compile_create_var (cfg
, &mono_defaults
.int_class
->byval_arg
, OP_ARG
);
1404 if (G_UNLIKELY (cfg
->verbose_level
> 1)) {
1405 printf ("vret_addr = ");
1406 mono_print_ins (cfg
->vret_addr
);
1411 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1412 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1416 * take the arguments and generate the arch-specific
1417 * instructions to properly call the function in call.
1418 * This includes pushing, moving arguments to the right register
1420 * Issue: who does the spilling if needed, and when?
1423 emit_sig_cookie (MonoCompile
*cfg
, MonoCallInst
*call
, CallInfo
*cinfo
)
1425 int sig_reg
= mono_alloc_ireg (cfg
);
1427 MONO_EMIT_NEW_ICONST (cfg
, sig_reg
, (guint32
)call
->signature
);
1428 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
,
1429 mips_sp
, cinfo
->sig_cookie
.offset
, sig_reg
);
1433 mono_arch_emit_call (MonoCompile
*cfg
, MonoCallInst
*call
)
1436 MonoMethodSignature
*sig
;
1441 sig
= call
->signature
;
1442 n
= sig
->param_count
+ sig
->hasthis
;
1444 cinfo
= calculate_sizes (sig
, sig
->pinvoke
);
1445 if (cinfo
->struct_ret
)
1446 call
->used_iregs
|= 1 << cinfo
->struct_ret
;
1448 for (i
= 0; i
< n
; ++i
) {
1449 ArgInfo
*ainfo
= cinfo
->args
+ i
;
1452 if (i
>= sig
->hasthis
)
1453 t
= sig
->params
[i
- sig
->hasthis
];
1455 t
= &mono_defaults
.int_class
->byval_arg
;
1456 t
= mini_type_get_underlying_type (cfg
->generic_sharing_context
, t
);
1458 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
))
1459 emit_sig_cookie (cfg
, call
, cinfo
);
1460 if (is_virtual
&& i
== 0) {
1461 /* the argument will be attached to the call instrucion */
1462 in
= call
->args
[i
];
1463 call
->used_iregs
|= 1 << ainfo
->reg
;
1466 in
= call
->args
[i
];
1467 if (ainfo
->regtype
== RegTypeGeneral
) {
1468 #if SIZEOF_REGISTER == 4
1469 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1470 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1471 ins
->dreg
= mono_alloc_ireg (cfg
);
1472 ins
->sreg1
= in
->dreg
+ 1;
1473 MONO_ADD_INS (cfg
->cbb
, ins
);
1474 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
+ 1, FALSE
);
1476 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1477 ins
->dreg
= mono_alloc_ireg (cfg
);
1478 ins
->sreg1
= in
->dreg
+ 2;
1479 MONO_ADD_INS (cfg
->cbb
, ins
);
1480 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1483 if (!t
->byref
&& (t
->type
== MONO_TYPE_R4
)) {
1486 #if PROMOTE_R4_TO_R8
1487 /* ??? - convert to single first? */
1488 MONO_INST_NEW (cfg
, ins
, OP_MIPS_CVTSD
);
1489 ins
->dreg
= mono_alloc_freg (cfg
);
1490 ins
->sreg1
= in
->dreg
;
1491 MONO_ADD_INS (cfg
->cbb
, ins
);
1496 /* trying to load float value into int registers */
1497 MONO_INST_NEW (cfg
, ins
, OP_MIPS_MFC1S
);
1498 ins
->dreg
= mono_alloc_ireg (cfg
);
1500 MONO_ADD_INS (cfg
->cbb
, ins
);
1501 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1502 } else if (!t
->byref
&& (t
->type
== MONO_TYPE_R8
)) {
1503 /* trying to load float value into int registers */
1504 MONO_INST_NEW (cfg
, ins
, OP_MIPS_MFC1D
);
1505 ins
->dreg
= mono_alloc_ireg (cfg
);
1506 ins
->sreg1
= in
->dreg
;
1507 MONO_ADD_INS (cfg
->cbb
, ins
);
1508 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1510 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1511 ins
->dreg
= mono_alloc_ireg (cfg
);
1512 ins
->sreg1
= in
->dreg
;
1513 MONO_ADD_INS (cfg
->cbb
, ins
);
1514 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1516 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
1517 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1518 ins
->opcode
= OP_OUTARG_VT
;
1519 ins
->sreg1
= in
->dreg
;
1520 ins
->klass
= in
->klass
;
1521 ins
->inst_p0
= call
;
1522 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1523 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1524 MONO_ADD_INS (cfg
->cbb
, ins
);
1525 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
1526 /* this is further handled in mono_arch_emit_outarg_vt () */
1527 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1528 ins
->opcode
= OP_OUTARG_VT
;
1529 ins
->sreg1
= in
->dreg
;
1530 ins
->klass
= in
->klass
;
1531 ins
->inst_p0
= call
;
1532 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1533 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1534 MONO_ADD_INS (cfg
->cbb
, ins
);
1535 } else if (ainfo
->regtype
== RegTypeBase
) {
1536 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1537 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1538 } else if (!t
->byref
&& ((t
->type
== MONO_TYPE_R4
) || (t
->type
== MONO_TYPE_R8
))) {
1539 if (t
->type
== MONO_TYPE_R8
)
1540 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER8_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1542 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER4_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1544 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_sp
, ainfo
->offset
, in
->dreg
);
1546 } else if (ainfo
->regtype
== RegTypeFP
) {
1547 if (t
->type
== MONO_TYPE_VALUETYPE
) {
1548 /* this is further handled in mono_arch_emit_outarg_vt () */
1549 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1550 ins
->opcode
= OP_OUTARG_VT
;
1551 ins
->sreg1
= in
->dreg
;
1552 ins
->klass
= in
->klass
;
1553 ins
->inst_p0
= call
;
1554 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1555 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1556 MONO_ADD_INS (cfg
->cbb
, ins
);
1558 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1560 int dreg
= mono_alloc_freg (cfg
);
1562 if (ainfo
->size
== 4) {
1563 MONO_EMIT_NEW_UNALU (cfg
, OP_MIPS_CVTSD
, dreg
, in
->dreg
);
1565 MONO_INST_NEW (cfg
, ins
, OP_FMOVE
);
1567 ins
->sreg1
= in
->dreg
;
1568 MONO_ADD_INS (cfg
->cbb
, ins
);
1571 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1572 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1575 g_assert_not_reached ();
1579 /* Emit the signature cookie in the case that there is no
1580 additional argument */
1581 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (n
== sig
->sentinelpos
))
1582 emit_sig_cookie (cfg
, call
, cinfo
);
1584 if (cinfo
->struct_ret
) {
1587 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
1588 vtarg
->sreg1
= call
->vret_var
->dreg
;
1589 vtarg
->dreg
= mono_alloc_preg (cfg
);
1590 MONO_ADD_INS (cfg
->cbb
, vtarg
);
1592 mono_call_inst_add_outarg_reg (cfg
, call
, vtarg
->dreg
, cinfo
->struct_ret
, FALSE
);
1596 * Reverse the call->out_args list.
1599 MonoInst
*prev
= NULL
, *list
= call
->out_args
, *next
;
1606 call
->out_args
= prev
;
1609 call
->stack_usage
= cinfo
->stack_usage
;
1610 cfg
->param_area
= MAX (cfg
->param_area
, cinfo
->stack_usage
);
1611 #if _MIPS_SIM == _ABIO32
1612 /* a0-a3 always present */
1613 cfg
->param_area
= MAX (cfg
->param_area
, 4 * SIZEOF_REGISTER
);
1615 cfg
->param_area
= (cfg
->param_area
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
1616 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
1618 * should set more info in call, such as the stack space
1619 * used by the args that needs to be added back to esp
1626 mono_arch_emit_outarg_vt (MonoCompile
*cfg
, MonoInst
*ins
, MonoInst
*src
)
1628 MonoCallInst
*call
= (MonoCallInst
*)ins
->inst_p0
;
1629 ArgInfo
*ainfo
= ins
->inst_p1
;
1630 int ovf_size
= ainfo
->vtsize
;
1631 int doffset
= ainfo
->offset
;
1632 int i
, soffset
, dreg
;
1634 if (ainfo
->regtype
== RegTypeStructByVal
) {
1636 if (cfg
->verbose_level
> 0) {
1637 char* nm
= mono_method_full_name (cfg
->method
, TRUE
);
1638 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1639 nm
, doffset
, ainfo
->size
, ovf_size
);
1645 for (i
= 0; i
< ainfo
->size
; ++i
) {
1646 dreg
= mono_alloc_ireg (cfg
);
1647 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, dreg
, src
->dreg
, soffset
);
1648 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
+ i
, FALSE
);
1649 soffset
+= SIZEOF_REGISTER
;
1651 if (ovf_size
!= 0) {
1652 mini_emit_memcpy (cfg
, mips_fp
, doffset
, src
->dreg
, soffset
, ovf_size
* sizeof (gpointer
), 0);
1654 } else if (ainfo
->regtype
== RegTypeFP
) {
1655 int tmpr
= mono_alloc_freg (cfg
);
1657 if (ainfo
->size
== 4)
1658 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR4_MEMBASE
, tmpr
, src
->dreg
, 0);
1660 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR8_MEMBASE
, tmpr
, src
->dreg
, 0);
1661 dreg
= mono_alloc_freg (cfg
);
1662 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, dreg
, tmpr
);
1663 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1665 MonoInst
*vtcopy
= mono_compile_create_var (cfg
, &src
->klass
->byval_arg
, OP_LOCAL
);
1669 /* FIXME: alignment? */
1670 if (call
->signature
->pinvoke
) {
1671 size
= mono_type_native_stack_size (&src
->klass
->byval_arg
, NULL
);
1672 vtcopy
->backend
.is_pinvoke
= 1;
1674 size
= mini_type_stack_size (cfg
->generic_sharing_context
, &src
->klass
->byval_arg
, NULL
);
1677 g_assert (ovf_size
> 0);
1679 EMIT_NEW_VARLOADA (cfg
, load
, vtcopy
, vtcopy
->inst_vtype
);
1680 mini_emit_memcpy (cfg
, load
->dreg
, 0, src
->dreg
, 0, size
, 0);
1683 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, mips_at
, ainfo
->offset
, load
->dreg
);
1685 mono_call_inst_add_outarg_reg (cfg
, call
, load
->dreg
, ainfo
->reg
, FALSE
);
1690 mono_arch_emit_setret (MonoCompile
*cfg
, MonoMethod
*method
, MonoInst
*val
)
1692 MonoType
*ret
= mini_type_get_underlying_type (cfg
->generic_sharing_context
,
1693 mono_method_signature (method
)->ret
);
1696 #if (SIZEOF_REGISTER == 4)
1697 if (ret
->type
== MONO_TYPE_I8
|| ret
->type
== MONO_TYPE_U8
) {
1700 MONO_INST_NEW (cfg
, ins
, OP_SETLRET
);
1701 ins
->sreg1
= val
->dreg
+ 1;
1702 ins
->sreg2
= val
->dreg
+ 2;
1703 MONO_ADD_INS (cfg
->cbb
, ins
);
1707 if (ret
->type
== MONO_TYPE_R8
) {
1708 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, cfg
->ret
->dreg
, val
->dreg
);
1711 if (ret
->type
== MONO_TYPE_R4
) {
1712 MONO_EMIT_NEW_UNALU (cfg
, OP_MIPS_CVTSD
, cfg
->ret
->dreg
, val
->dreg
);
1716 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, cfg
->ret
->dreg
, val
->dreg
);
1720 mono_arch_peephole_pass_1 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1722 MonoInst
*ins
, *n
, *last_ins
= NULL
;
1724 if (cfg
->verbose_level
> 2)
1725 g_print ("Basic block %d peephole pass 1\n", bb
->block_num
);
1728 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
1729 if (cfg
->verbose_level
> 2)
1730 mono_print_ins_index (0, ins
);
1732 switch (ins
->opcode
) {
1734 case OP_LOAD_MEMBASE
:
1735 case OP_LOADI4_MEMBASE
:
1737 * OP_IADD reg2, reg1, const1
1738 * OP_LOAD_MEMBASE const2(reg2), reg3
1740 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1742 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
)){
1743 int const1
= last_ins
->inst_imm
;
1744 int const2
= ins
->inst_offset
;
1746 if (mips_is_imm16 (const1
+ const2
)) {
1747 ins
->inst_basereg
= last_ins
->sreg1
;
1748 ins
->inst_offset
= const1
+ const2
;
1758 bb
->last_ins
= last_ins
;
1762 mono_arch_peephole_pass_2 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1764 MonoInst
*ins
, *n
, *last_ins
= NULL
;
1767 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
1768 MonoInst
*last_ins
= ins
->prev
;
1770 switch (ins
->opcode
) {
1772 /* remove unnecessary multiplication with 1 */
1773 if (ins
->inst_imm
== 1) {
1774 if (ins
->dreg
!= ins
->sreg1
) {
1775 ins
->opcode
= OP_MOVE
;
1777 MONO_DELETE_INS (bb
, ins
);
1781 int power2
= mono_is_power_of_two (ins
->inst_imm
);
1783 ins
->opcode
= OP_SHL_IMM
;
1784 ins
->inst_imm
= power2
;
1788 case OP_LOAD_MEMBASE
:
1789 case OP_LOADI4_MEMBASE
:
1791 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1792 * OP_LOAD_MEMBASE offset(basereg), reg
1794 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_REG
1795 || last_ins
->opcode
== OP_STORE_MEMBASE_REG
) &&
1796 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1797 ins
->inst_offset
== last_ins
->inst_offset
) {
1798 if (ins
->dreg
== last_ins
->sreg1
) {
1799 MONO_DELETE_INS (bb
, ins
);
1802 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1803 ins
->opcode
= OP_MOVE
;
1804 ins
->sreg1
= last_ins
->sreg1
;
1809 * Note: reg1 must be different from the basereg in the second load
1810 * OP_LOAD_MEMBASE offset(basereg), reg1
1811 * OP_LOAD_MEMBASE offset(basereg), reg2
1813 * OP_LOAD_MEMBASE offset(basereg), reg1
1814 * OP_MOVE reg1, reg2
1816 if (last_ins
&& (last_ins
->opcode
== OP_LOADI4_MEMBASE
1817 || last_ins
->opcode
== OP_LOAD_MEMBASE
) &&
1818 ins
->inst_basereg
!= last_ins
->dreg
&&
1819 ins
->inst_basereg
== last_ins
->inst_basereg
&&
1820 ins
->inst_offset
== last_ins
->inst_offset
) {
1822 if (ins
->dreg
== last_ins
->dreg
) {
1823 MONO_DELETE_INS (bb
, ins
);
1826 ins
->opcode
= OP_MOVE
;
1827 ins
->sreg1
= last_ins
->dreg
;
1830 //g_assert_not_reached ();
1835 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1836 * OP_LOAD_MEMBASE offset(basereg), reg
1838 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1839 * OP_ICONST reg, imm
1841 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_IMM
1842 || last_ins
->opcode
== OP_STORE_MEMBASE_IMM
) &&
1843 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1844 ins
->inst_offset
== last_ins
->inst_offset
) {
1845 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1846 ins
->opcode
= OP_ICONST
;
1847 ins
->inst_c0
= last_ins
->inst_imm
;
1848 g_assert_not_reached (); // check this rule
1853 case OP_LOADU1_MEMBASE
:
1854 case OP_LOADI1_MEMBASE
:
1855 if (last_ins
&& (last_ins
->opcode
== OP_STOREI1_MEMBASE_REG
) &&
1856 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1857 ins
->inst_offset
== last_ins
->inst_offset
) {
1858 ins
->opcode
= (ins
->opcode
== OP_LOADI1_MEMBASE
) ? OP_ICONV_TO_I1
: OP_ICONV_TO_U1
;
1859 ins
->sreg1
= last_ins
->sreg1
;
1862 case OP_LOADU2_MEMBASE
:
1863 case OP_LOADI2_MEMBASE
:
1864 if (last_ins
&& (last_ins
->opcode
== OP_STOREI2_MEMBASE_REG
) &&
1865 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1866 ins
->inst_offset
== last_ins
->inst_offset
) {
1867 ins
->opcode
= (ins
->opcode
== OP_LOADI2_MEMBASE
) ? OP_ICONV_TO_I2
: OP_ICONV_TO_U2
;
1868 ins
->sreg1
= last_ins
->sreg1
;
1871 case OP_ICONV_TO_I4
:
1872 case OP_ICONV_TO_U4
:
1874 ins
->opcode
= OP_MOVE
;
1878 if (ins
->dreg
== ins
->sreg1
) {
1879 MONO_DELETE_INS (bb
, ins
);
1883 * OP_MOVE sreg, dreg
1884 * OP_MOVE dreg, sreg
1886 if (last_ins
&& last_ins
->opcode
== OP_MOVE
&&
1887 ins
->sreg1
== last_ins
->dreg
&&
1888 ins
->dreg
== last_ins
->sreg1
) {
1889 MONO_DELETE_INS (bb
, ins
);
1897 bb
->last_ins
= last_ins
;
1901 mono_arch_decompose_long_opts (MonoCompile
*cfg
, MonoInst
*ins
)
1909 switch (ins
->opcode
) {
1912 case OP_LCOMPARE_IMM
:
1913 mono_print_ins (ins
);
1914 g_assert_not_reached ();
1917 tmp1
= mono_alloc_ireg (cfg
);
1918 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
1919 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
1920 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
1921 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
1922 ins
->opcode
= OP_NOP
;
1926 tmp1
= mono_alloc_ireg (cfg
);
1927 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, ins
->dreg
+1, ins
->sreg1
+1, ins
->inst_ls_word
);
1928 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
1929 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, ins
->dreg
+2, ins
->sreg1
+2, ins
->inst_ms_word
);
1930 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
1931 ins
->opcode
= OP_NOP
;
1935 tmp1
= mono_alloc_ireg (cfg
);
1936 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
1937 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
1938 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
1939 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
1940 ins
->opcode
= OP_NOP
;
1944 tmp1
= mono_alloc_ireg (cfg
);
1945 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, ins
->dreg
+1, ins
->sreg1
+1, ins
->inst_ls_word
);
1946 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
1947 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, ins
->dreg
+2, ins
->sreg1
+2, ins
->inst_ms_word
);
1948 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
1949 ins
->opcode
= OP_NOP
;
1960 mono_print_ins (ins
);
1961 g_assert_not_reached ();
1964 tmp1
= mono_alloc_ireg (cfg
);
1965 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, mips_zero
, ins
->sreg1
+1);
1966 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, mips_zero
, ins
->dreg
+1);
1967 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, mips_zero
, ins
->sreg1
+2);
1968 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
1969 ins
->opcode
= OP_NOP
;
1976 case OP_LCONV_TO_I1
:
1977 case OP_LCONV_TO_I2
:
1978 case OP_LCONV_TO_I4
:
1979 case OP_LCONV_TO_I8
:
1980 case OP_LCONV_TO_R4
:
1981 case OP_LCONV_TO_R8
:
1982 case OP_LCONV_TO_U4
:
1983 case OP_LCONV_TO_U8
:
1984 case OP_LCONV_TO_U2
:
1985 case OP_LCONV_TO_U1
:
1987 case OP_LCONV_TO_OVF_I
:
1988 case OP_LCONV_TO_OVF_U
:
1990 mono_print_ins (ins
);
1991 g_assert_not_reached ();
1994 tmp1
= mono_alloc_ireg (cfg
);
1995 tmp2
= mono_alloc_ireg (cfg
);
1996 tmp3
= mono_alloc_ireg (cfg
);
1997 tmp4
= mono_alloc_ireg (cfg
);
1998 tmp5
= mono_alloc_ireg (cfg
);
2000 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2002 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2003 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp5
, ins
->dreg
+1, ins
->sreg1
+1);
2005 /* add the high 32-bits, and add in the carry from the low 32-bits */
2006 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2007 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, tmp5
, ins
->dreg
+2);
2009 /* Overflow happens if
2010 * neg + neg = pos or
2012 * XOR of the high bits returns 0 if the signs match
2013 * XOR of that with the high bit of the result return 1 if overflow.
2016 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2017 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
+2, ins
->sreg2
+2);
2019 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2020 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->dreg
+2, ins
->sreg2
+2);
2021 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tmp2
, tmp2
);
2023 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2024 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tmp3
, tmp2
, tmp1
);
2025 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp4
, tmp3
, 31);
2027 /* Now, if (tmp4 == 0) then overflow */
2028 MONO_EMIT_NEW_COMPARE_EXC (cfg
, EQ
, tmp4
, mips_zero
, "OverflowException");
2029 ins
->opcode
= OP_NOP
;
2032 case OP_LADD_OVF_UN
:
2033 tmp1
= mono_alloc_ireg (cfg
);
2034 tmp2
= mono_alloc_ireg (cfg
);
2036 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2037 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
+1, ins
->sreg1
+1);
2038 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2039 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
+2, tmp1
, ins
->dreg
+2);
2040 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp2
, ins
->dreg
+2, ins
->sreg1
+2);
2041 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp2
, mips_zero
, "OverflowException");
2042 ins
->opcode
= OP_NOP
;
2046 case OP_LMUL_OVF_UN
:
2047 mono_print_ins (ins
);
2048 g_assert_not_reached ();
2051 tmp1
= mono_alloc_ireg (cfg
);
2052 tmp2
= mono_alloc_ireg (cfg
);
2053 tmp3
= mono_alloc_ireg (cfg
);
2054 tmp4
= mono_alloc_ireg (cfg
);
2055 tmp5
= mono_alloc_ireg (cfg
);
2057 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2059 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp5
, ins
->sreg1
+1, ins
->dreg
+1);
2060 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2061 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp5
);
2063 /* Overflow happens if
2064 * neg - pos = pos or
2066 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2068 * tmp1 = (lhs ^ rhs)
2069 * tmp2 = (lhs ^ result)
2070 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2073 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
+2, ins
->sreg2
+2);
2074 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->sreg1
+2, ins
->dreg
+2);
2075 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tmp3
, tmp2
, tmp1
);
2076 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp4
, tmp3
, 31);
2078 /* Now, if (tmp4 == 1) then overflow */
2079 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp4
, mips_zero
, "OverflowException");
2080 ins
->opcode
= OP_NOP
;
2083 case OP_LSUB_OVF_UN
:
2084 tmp1
= mono_alloc_ireg (cfg
);
2085 tmp2
= mono_alloc_ireg (cfg
);
2087 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+1, ins
->sreg1
+1, ins
->sreg2
+1);
2088 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
+1, ins
->dreg
+1);
2089 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->sreg1
+2, ins
->sreg2
+2);
2090 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
+2, ins
->dreg
+2, tmp1
);
2092 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp2
, ins
->sreg1
+2, ins
->dreg
+2);
2093 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp2
, mips_zero
, "OverflowException");
2094 ins
->opcode
= OP_NOP
;
2097 case OP_LCONV_TO_OVF_I1_UN
:
2098 case OP_LCONV_TO_OVF_I2_UN
:
2099 case OP_LCONV_TO_OVF_I4_UN
:
2100 case OP_LCONV_TO_OVF_I8_UN
:
2101 case OP_LCONV_TO_OVF_U1_UN
:
2102 case OP_LCONV_TO_OVF_U2_UN
:
2103 case OP_LCONV_TO_OVF_U4_UN
:
2104 case OP_LCONV_TO_OVF_U8_UN
:
2105 case OP_LCONV_TO_OVF_I_UN
:
2106 case OP_LCONV_TO_OVF_U_UN
:
2107 case OP_LCONV_TO_OVF_I1
:
2108 case OP_LCONV_TO_OVF_U1
:
2109 case OP_LCONV_TO_OVF_I2
:
2110 case OP_LCONV_TO_OVF_U2
:
2111 case OP_LCONV_TO_OVF_I4
:
2112 case OP_LCONV_TO_OVF_U4
:
2113 case OP_LCONV_TO_OVF_I8
:
2114 case OP_LCONV_TO_OVF_U8
:
2122 case OP_LCONV_TO_R_UN
:
2128 case OP_LSHR_UN_IMM
:
2130 case OP_LDIV_UN_IMM
:
2132 case OP_LREM_UN_IMM
:
2143 mono_print_ins (ins
);
2144 g_assert_not_reached ();
2146 case OP_LCONV_TO_R8_2
:
2147 case OP_LCONV_TO_R4_2
:
2148 case OP_LCONV_TO_R_UN_2
:
2150 case OP_LCONV_TO_OVF_I4_2
:
2151 tmp1
= mono_alloc_ireg (cfg
);
2153 /* Overflows if reg2 != sign extension of reg1 */
2154 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp1
, ins
->sreg1
, 31);
2155 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, ins
->sreg2
, tmp1
, "OverflowException");
2156 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
2157 ins
->opcode
= OP_NOP
;
2164 mono_print_ins (ins
);
2165 g_assert_not_reached ();
2173 mono_arch_decompose_opts (MonoCompile
*cfg
, MonoInst
*ins
)
2181 switch (ins
->opcode
) {
2183 tmp1
= mono_alloc_ireg (cfg
);
2184 tmp2
= mono_alloc_ireg (cfg
);
2185 tmp3
= mono_alloc_ireg (cfg
);
2186 tmp4
= mono_alloc_ireg (cfg
);
2187 tmp5
= mono_alloc_ireg (cfg
);
2189 /* add the operands */
2191 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2193 /* Overflow happens if
2194 * neg + neg = pos or
2197 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2198 * XOR of the high bit returns 0 if the signs match
2199 * XOR of that with the high bit of the result return 1 if overflow.
2202 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2203 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
, ins
->sreg2
);
2205 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2206 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->dreg
, ins
->sreg2
);
2207 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tmp3
, tmp2
);
2209 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2210 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tmp4
, tmp3
, tmp1
);
2212 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tmp5
, tmp4
, 31);
2214 /* Now, if (tmp4 == 0) then overflow */
2215 MONO_EMIT_NEW_COMPARE_EXC (cfg
, EQ
, tmp5
, mips_zero
, "OverflowException");
2216 ins
->opcode
= OP_NOP
;
2219 case OP_IADD_OVF_UN
:
2220 tmp1
= mono_alloc_ireg (cfg
);
2222 MONO_EMIT_NEW_BIALU (cfg
, OP_IADD
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2223 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->dreg
, ins
->sreg1
);
2224 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp1
, mips_zero
, "OverflowException");
2225 ins
->opcode
= OP_NOP
;
2229 tmp1
= mono_alloc_ireg (cfg
);
2230 tmp2
= mono_alloc_ireg (cfg
);
2231 tmp3
= mono_alloc_ireg (cfg
);
2232 tmp4
= mono_alloc_ireg (cfg
);
2233 tmp5
= mono_alloc_ireg (cfg
);
2235 /* add the operands */
2237 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2239 /* Overflow happens if
2240 * neg - pos = pos or
2242 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2244 * tmp1 = (lhs ^ rhs)
2245 * tmp2 = (lhs ^ result)
2246 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2249 /* tmp3 = 1 if the signs of the two inputs differ */
2250 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp1
, ins
->sreg1
, ins
->sreg2
);
2251 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tmp2
, ins
->sreg1
, ins
->dreg
);
2252 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_MIPS_SLTI
, tmp3
, tmp1
, 0);
2253 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_MIPS_SLTI
, tmp4
, tmp2
, 0);
2254 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tmp5
, tmp4
, tmp3
);
2256 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp5
, mips_zero
, "OverflowException");
2257 ins
->opcode
= OP_NOP
;
2260 case OP_ISUB_OVF_UN
:
2261 tmp1
= mono_alloc_ireg (cfg
);
2263 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUB
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2264 MONO_EMIT_NEW_BIALU (cfg
, OP_MIPS_SLTU
, tmp1
, ins
->sreg1
, ins
->dreg
);
2265 MONO_EMIT_NEW_COMPARE_EXC (cfg
, NE_UN
, tmp1
, mips_zero
, "OverflowException");
2266 ins
->opcode
= OP_NOP
;
2273 map_to_reg_reg_op (int op
)
2282 case OP_COMPARE_IMM
:
2284 case OP_ICOMPARE_IMM
:
2286 case OP_LCOMPARE_IMM
:
2302 case OP_LOAD_MEMBASE
:
2303 return OP_LOAD_MEMINDEX
;
2304 case OP_LOADI4_MEMBASE
:
2305 return OP_LOADI4_MEMINDEX
;
2306 case OP_LOADU4_MEMBASE
:
2307 return OP_LOADU4_MEMINDEX
;
2308 case OP_LOADU1_MEMBASE
:
2309 return OP_LOADU1_MEMINDEX
;
2310 case OP_LOADI2_MEMBASE
:
2311 return OP_LOADI2_MEMINDEX
;
2312 case OP_LOADU2_MEMBASE
:
2313 return OP_LOADU2_MEMINDEX
;
2314 case OP_LOADI1_MEMBASE
:
2315 return OP_LOADI1_MEMINDEX
;
2316 case OP_LOADR4_MEMBASE
:
2317 return OP_LOADR4_MEMINDEX
;
2318 case OP_LOADR8_MEMBASE
:
2319 return OP_LOADR8_MEMINDEX
;
2320 case OP_STOREI1_MEMBASE_REG
:
2321 return OP_STOREI1_MEMINDEX
;
2322 case OP_STOREI2_MEMBASE_REG
:
2323 return OP_STOREI2_MEMINDEX
;
2324 case OP_STOREI4_MEMBASE_REG
:
2325 return OP_STOREI4_MEMINDEX
;
2326 case OP_STORE_MEMBASE_REG
:
2327 return OP_STORE_MEMINDEX
;
2328 case OP_STORER4_MEMBASE_REG
:
2329 return OP_STORER4_MEMINDEX
;
2330 case OP_STORER8_MEMBASE_REG
:
2331 return OP_STORER8_MEMINDEX
;
2332 case OP_STORE_MEMBASE_IMM
:
2333 return OP_STORE_MEMBASE_REG
;
2334 case OP_STOREI1_MEMBASE_IMM
:
2335 return OP_STOREI1_MEMBASE_REG
;
2336 case OP_STOREI2_MEMBASE_IMM
:
2337 return OP_STOREI2_MEMBASE_REG
;
2338 case OP_STOREI4_MEMBASE_IMM
:
2339 return OP_STOREI4_MEMBASE_REG
;
2340 case OP_STOREI8_MEMBASE_IMM
:
2341 return OP_STOREI8_MEMBASE_REG
;
2343 return mono_op_imm_to_op (op
);
2347 map_to_mips_op (int op
)
2351 return OP_MIPS_FBEQ
;
2353 return OP_MIPS_FBGE
;
2355 return OP_MIPS_FBGT
;
2357 return OP_MIPS_FBLE
;
2359 return OP_MIPS_FBLT
;
2361 return OP_MIPS_FBNE
;
2363 return OP_MIPS_FBGE_UN
;
2365 return OP_MIPS_FBGT_UN
;
2367 return OP_MIPS_FBLE_UN
;
2369 return OP_MIPS_FBLT_UN
;
2377 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op
), __FUNCTION__
);
2378 g_assert_not_reached ();
2382 #define NEW_INS(cfg,after,dest,op) do { \
2383 MONO_INST_NEW((cfg), (dest), (op)); \
2384 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2387 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2389 MONO_INST_NEW(cfg, temp, (op)); \
2390 mono_bblock_insert_after_ins (bb, (pos), temp); \
2391 temp->dreg = (_dreg); \
2392 temp->sreg1 = (_sreg1); \
2393 temp->sreg2 = (_sreg2); \
2397 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2399 MONO_INST_NEW(cfg, temp, (op)); \
2400 mono_bblock_insert_after_ins (bb, (pos), temp); \
2401 temp->dreg = (_dreg); \
2402 temp->sreg1 = (_sreg1); \
2403 temp->inst_c0 = (_imm); \
2408 * Remove from the instruction list the instructions that can't be
2409 * represented with very simple instructions with no register
2413 mono_arch_lowering_pass (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2415 MonoInst
*ins
, *next
, *temp
, *last_ins
= NULL
;
2419 if (cfg
->verbose_level
> 2) {
2422 g_print ("BASIC BLOCK %d (before lowering)\n", bb
->block_num
);
2423 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2424 mono_print_ins_index (idx
++, ins
);
2430 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2432 switch (ins
->opcode
) {
2437 /* Branch opts can eliminate the branch */
2438 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2439 ins
->opcode
= OP_NOP
;
2444 case OP_COMPARE_IMM
:
2445 case OP_ICOMPARE_IMM
:
2446 case OP_LCOMPARE_IMM
:
2448 /* Branch opts can eliminate the branch */
2449 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2450 ins
->opcode
= OP_NOP
;
2453 if (ins
->inst_imm
) {
2454 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2455 temp
->inst_c0
= ins
->inst_imm
;
2456 temp
->dreg
= mono_alloc_ireg (cfg
);
2457 ins
->sreg2
= temp
->dreg
;
2461 ins
->sreg2
= mips_zero
;
2463 if (ins
->opcode
== OP_COMPARE_IMM
)
2464 ins
->opcode
= OP_COMPARE
;
2465 else if (ins
->opcode
== OP_ICOMPARE_IMM
)
2466 ins
->opcode
= OP_ICOMPARE
;
2467 else if (ins
->opcode
== OP_LCOMPARE_IMM
)
2468 ins
->opcode
= OP_LCOMPARE
;
2471 case OP_IDIV_UN_IMM
:
2474 case OP_IREM_UN_IMM
:
2475 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2476 temp
->inst_c0
= ins
->inst_imm
;
2477 temp
->dreg
= mono_alloc_ireg (cfg
);
2478 ins
->sreg2
= temp
->dreg
;
2479 if (ins
->opcode
== OP_IDIV_IMM
)
2480 ins
->opcode
= OP_IDIV
;
2481 else if (ins
->opcode
== OP_IREM_IMM
)
2482 ins
->opcode
= OP_IREM
;
2483 else if (ins
->opcode
== OP_IDIV_UN_IMM
)
2484 ins
->opcode
= OP_IDIV_UN
;
2485 else if (ins
->opcode
== OP_IREM_UN_IMM
)
2486 ins
->opcode
= OP_IREM_UN
;
2488 /* handle rem separately */
2495 if ((ins
->inst_imm
& 0xffff0000) && (ins
->inst_imm
& 0xffff)) {
2496 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2497 temp
->inst_c0
= ins
->inst_imm
;
2498 temp
->dreg
= mono_alloc_ireg (cfg
);
2499 ins
->sreg2
= temp
->dreg
;
2500 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2510 /* unsigned 16 bit immediate */
2511 if (ins
->inst_imm
& 0xffff0000) {
2512 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2513 temp
->inst_c0
= ins
->inst_imm
;
2514 temp
->dreg
= mono_alloc_ireg (cfg
);
2515 ins
->sreg2
= temp
->dreg
;
2516 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2523 /* signed 16 bit immediate */
2524 if (!mips_is_imm16 (ins
->inst_imm
)) {
2525 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2526 temp
->inst_c0
= ins
->inst_imm
;
2527 temp
->dreg
= mono_alloc_ireg (cfg
);
2528 ins
->sreg2
= temp
->dreg
;
2529 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2535 if (!mips_is_imm16 (-ins
->inst_imm
)) {
2536 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2537 temp
->inst_c0
= ins
->inst_imm
;
2538 temp
->dreg
= mono_alloc_ireg (cfg
);
2539 ins
->sreg2
= temp
->dreg
;
2540 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2546 if (ins
->inst_imm
== 1) {
2547 ins
->opcode
= OP_MOVE
;
2550 if (ins
->inst_imm
== 0) {
2551 ins
->opcode
= OP_ICONST
;
2555 imm
= mono_is_power_of_two (ins
->inst_imm
);
2557 ins
->opcode
= OP_SHL_IMM
;
2558 ins
->inst_imm
= imm
;
2561 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2562 temp
->inst_c0
= ins
->inst_imm
;
2563 temp
->dreg
= mono_alloc_ireg (cfg
);
2564 ins
->sreg2
= temp
->dreg
;
2565 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2568 case OP_LOCALLOC_IMM
:
2569 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2570 temp
->inst_c0
= ins
->inst_imm
;
2571 temp
->dreg
= mono_alloc_ireg (cfg
);
2572 ins
->sreg1
= temp
->dreg
;
2573 ins
->opcode
= OP_LOCALLOC
;
2576 case OP_LOAD_MEMBASE
:
2577 case OP_LOADI4_MEMBASE
:
2578 case OP_LOADU4_MEMBASE
:
2579 case OP_LOADI2_MEMBASE
:
2580 case OP_LOADU2_MEMBASE
:
2581 case OP_LOADI1_MEMBASE
:
2582 case OP_LOADU1_MEMBASE
:
2583 case OP_LOADR4_MEMBASE
:
2584 case OP_LOADR8_MEMBASE
:
2585 case OP_STORE_MEMBASE_REG
:
2586 case OP_STOREI4_MEMBASE_REG
:
2587 case OP_STOREI2_MEMBASE_REG
:
2588 case OP_STOREI1_MEMBASE_REG
:
2589 case OP_STORER4_MEMBASE_REG
:
2590 case OP_STORER8_MEMBASE_REG
:
2591 /* we can do two things: load the immed in a register
2592 * and use an indexed load, or see if the immed can be
2593 * represented as an ad_imm + a load with a smaller offset
2594 * that fits. We just do the first for now, optimize later.
2596 if (mips_is_imm16 (ins
->inst_offset
))
2598 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2599 temp
->inst_c0
= ins
->inst_offset
;
2600 temp
->dreg
= mono_alloc_ireg (cfg
);
2601 ins
->sreg2
= temp
->dreg
;
2602 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2605 case OP_STORE_MEMBASE_IMM
:
2606 case OP_STOREI1_MEMBASE_IMM
:
2607 case OP_STOREI2_MEMBASE_IMM
:
2608 case OP_STOREI4_MEMBASE_IMM
:
2609 case OP_STOREI8_MEMBASE_IMM
:
2610 if (!ins
->inst_imm
) {
2611 ins
->sreg1
= mips_zero
;
2612 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2615 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2616 temp
->inst_c0
= ins
->inst_imm
;
2617 temp
->dreg
= mono_alloc_ireg (cfg
);
2618 ins
->sreg1
= temp
->dreg
;
2619 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2621 goto loop_start
; /* make it handle the possibly big ins->inst_offset */
2627 /* Branch opts can eliminate the branch */
2628 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2629 ins
->opcode
= OP_NOP
;
2635 * remap compare/branch and compare/set
2636 * to MIPS specific opcodes.
2638 ins
->opcode
= OP_NOP
;
2639 next
->opcode
= map_to_mips_op (next
->opcode
);
2640 next
->sreg1
= ins
->sreg1
;
2641 next
->sreg2
= ins
->sreg2
;
2647 NEW_INS (cfg
, last_ins
, temp
, OP_ICONST
);
2648 temp
->inst_c0
= (guint32
)ins
->inst_p0
;
2649 temp
->dreg
= mono_alloc_ireg (cfg
);
2650 ins
->inst_basereg
= temp
->dreg
;
2651 ins
->inst_offset
= 0;
2652 ins
->opcode
= ins
->opcode
== OP_R4CONST
? OP_LOADR4_MEMBASE
: OP_LOADR8_MEMBASE
;
2654 /* make it handle the possibly big ins->inst_offset
2655 * later optimize to use lis + load_membase
2660 g_assert (ins_is_compare(last_ins
));
2661 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->sreg1
, last_ins
->sreg2
);
2662 last_ins
->opcode
= OP_NOP
;
2666 g_assert (ins_is_compare(last_ins
));
2667 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->sreg1
, last_ins
->sreg2
);
2668 last_ins
->opcode
= OP_NOP
;
2672 g_assert (ins_is_compare(last_ins
));
2673 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2674 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2675 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2679 g_assert (ins_is_compare(last_ins
));
2680 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2681 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2682 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2686 g_assert (ins_is_compare(last_ins
));
2687 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2688 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2689 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2693 g_assert (ins_is_compare(last_ins
));
2694 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2695 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2696 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2700 g_assert (ins_is_compare(last_ins
));
2701 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2702 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2703 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2707 g_assert (ins_is_compare(last_ins
));
2708 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2709 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2710 INS_REWRITE(ins
, OP_MIPS_BEQ
, last_ins
->dreg
, mips_zero
);
2714 g_assert (ins_is_compare(last_ins
));
2715 INS_REWRITE(last_ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2716 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2717 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2721 g_assert (ins_is_compare(last_ins
));
2722 INS_REWRITE(last_ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2723 last_ins
->dreg
= mono_alloc_ireg (cfg
);
2724 INS_REWRITE(ins
, OP_MIPS_BNE
, last_ins
->dreg
, mips_zero
);
2729 g_assert (ins_is_compare(last_ins
));
2730 last_ins
->opcode
= OP_IXOR
;
2731 last_ins
->dreg
= mono_alloc_ireg(cfg
);
2732 INS_REWRITE_IMM(ins
, OP_MIPS_SLTIU
, last_ins
->dreg
, 1);
2737 INS_REWRITE(ins
, OP_MIPS_SLT
, last_ins
->sreg1
, last_ins
->sreg2
);
2738 last_ins
->opcode
= OP_NOP
;
2744 INS_REWRITE(ins
, OP_MIPS_SLTU
, last_ins
->sreg1
, last_ins
->sreg2
);
2745 last_ins
->opcode
= OP_NOP
;
2750 g_assert (ins_is_compare(last_ins
));
2751 INS_REWRITE(ins
, OP_MIPS_SLT
, last_ins
->sreg2
, last_ins
->sreg1
);
2752 MONO_DELETE_INS(bb
, last_ins
);
2757 g_assert (ins_is_compare(last_ins
));
2758 INS_REWRITE(ins
, OP_MIPS_SLTU
, last_ins
->sreg2
, last_ins
->sreg1
);
2759 MONO_DELETE_INS(bb
, last_ins
);
2762 case OP_COND_EXC_EQ
:
2763 case OP_COND_EXC_IEQ
:
2764 g_assert (ins_is_compare(last_ins
));
2765 INS_REWRITE(ins
, OP_MIPS_COND_EXC_EQ
, last_ins
->sreg1
, last_ins
->sreg2
);
2766 MONO_DELETE_INS(bb
, last_ins
);
2769 case OP_COND_EXC_GE
:
2770 case OP_COND_EXC_IGE
:
2771 g_assert (ins_is_compare(last_ins
));
2772 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GE
, last_ins
->sreg1
, last_ins
->sreg2
);
2773 MONO_DELETE_INS(bb
, last_ins
);
2776 case OP_COND_EXC_GT
:
2777 case OP_COND_EXC_IGT
:
2778 g_assert (ins_is_compare(last_ins
));
2779 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GT
, last_ins
->sreg1
, last_ins
->sreg2
);
2780 MONO_DELETE_INS(bb
, last_ins
);
2783 case OP_COND_EXC_LE
:
2784 case OP_COND_EXC_ILE
:
2785 g_assert (ins_is_compare(last_ins
));
2786 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LE
, last_ins
->sreg1
, last_ins
->sreg2
);
2787 MONO_DELETE_INS(bb
, last_ins
);
2790 case OP_COND_EXC_LT
:
2791 case OP_COND_EXC_ILT
:
2792 g_assert (ins_is_compare(last_ins
));
2793 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LT
, last_ins
->sreg1
, last_ins
->sreg2
);
2794 MONO_DELETE_INS(bb
, last_ins
);
2797 case OP_COND_EXC_NE_UN
:
2798 case OP_COND_EXC_INE_UN
:
2799 g_assert (ins_is_compare(last_ins
));
2800 INS_REWRITE(ins
, OP_MIPS_COND_EXC_NE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2801 MONO_DELETE_INS(bb
, last_ins
);
2804 case OP_COND_EXC_GE_UN
:
2805 case OP_COND_EXC_IGE_UN
:
2806 g_assert (ins_is_compare(last_ins
));
2807 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2808 MONO_DELETE_INS(bb
, last_ins
);
2811 case OP_COND_EXC_GT_UN
:
2812 case OP_COND_EXC_IGT_UN
:
2813 g_assert (ins_is_compare(last_ins
));
2814 INS_REWRITE(ins
, OP_MIPS_COND_EXC_GT_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2815 MONO_DELETE_INS(bb
, last_ins
);
2818 case OP_COND_EXC_LE_UN
:
2819 case OP_COND_EXC_ILE_UN
:
2820 g_assert (ins_is_compare(last_ins
));
2821 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LE_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2822 MONO_DELETE_INS(bb
, last_ins
);
2825 case OP_COND_EXC_LT_UN
:
2826 case OP_COND_EXC_ILT_UN
:
2827 g_assert (ins_is_compare(last_ins
));
2828 INS_REWRITE(ins
, OP_MIPS_COND_EXC_LT_UN
, last_ins
->sreg1
, last_ins
->sreg2
);
2829 MONO_DELETE_INS(bb
, last_ins
);
2832 case OP_COND_EXC_OV
:
2833 case OP_COND_EXC_IOV
: {
2834 int tmp1
, tmp2
, tmp3
, tmp4
, tmp5
;
2835 MonoInst
*pos
= last_ins
;
2837 /* Overflow happens if
2838 * neg + neg = pos or
2841 * (bit31s of operands match) AND (bit31 of operand
2842 * != bit31 of result)
2843 * XOR of the high bit returns 0 if the signs match
2844 * XOR of that with the high bit of the result return 1
2847 g_assert (last_ins
->opcode
== OP_IADC
);
2849 tmp1
= mono_alloc_ireg (cfg
);
2850 tmp2
= mono_alloc_ireg (cfg
);
2851 tmp3
= mono_alloc_ireg (cfg
);
2852 tmp4
= mono_alloc_ireg (cfg
);
2853 tmp5
= mono_alloc_ireg (cfg
);
2855 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2856 INS (pos
, OP_IXOR
, tmp1
, last_ins
->sreg1
, last_ins
->sreg2
);
2858 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2859 INS (pos
, OP_IXOR
, tmp2
, last_ins
->dreg
, last_ins
->sreg2
);
2860 INS (pos
, OP_INOT
, tmp3
, tmp2
, -1);
2862 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2863 INS (pos
, OP_IOR
, tmp4
, tmp3
, tmp1
);
2864 INS_IMM (pos
, OP_SHR_IMM
, tmp5
, tmp4
, 31);
2866 /* Now, if (tmp5 == 0) then overflow */
2867 INS_REWRITE(ins
, OP_MIPS_COND_EXC_EQ
, tmp5
, mips_zero
);
2872 case OP_COND_EXC_NO
:
2873 case OP_COND_EXC_INO
:
2874 g_assert_not_reached ();
2878 case OP_COND_EXC_IC
:
2879 g_assert_not_reached ();
2882 case OP_COND_EXC_NC
:
2883 case OP_COND_EXC_INC
:
2884 g_assert_not_reached ();
2890 bb
->last_ins
= last_ins
;
2891 bb
->max_vreg
= cfg
->next_vreg
;
2894 if (cfg
->verbose_level
> 2) {
2897 g_print ("BASIC BLOCK %d (after lowering)\n", bb
->block_num
);
2898 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2899 mono_print_ins_index (idx
++, ins
);
2908 emit_float_to_int (MonoCompile
*cfg
, guchar
*code
, int dreg
, int sreg
, int size
, gboolean is_signed
)
2910 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
2912 mips_truncwd (code
, mips_ftemp
, sreg
);
2914 mips_cvtwd (code
, mips_ftemp
, sreg
);
2916 mips_mfc1 (code
, dreg
, mips_ftemp
);
2919 mips_andi (code
, dreg
, dreg
, 0xff);
2920 else if (size
== 2) {
2921 mips_sll (code
, dreg
, dreg
, 16);
2922 mips_srl (code
, dreg
, dreg
, 16);
2926 mips_sll (code
, dreg
, dreg
, 24);
2927 mips_sra (code
, dreg
, dreg
, 24);
2929 else if (size
== 2) {
2930 mips_sll (code
, dreg
, dreg
, 16);
2931 mips_sra (code
, dreg
, dreg
, 16);
2938 * emit_load_volatile_arguments:
2940 * Load volatile arguments from the stack to the original input registers.
2941 * Required before a tail call.
2944 emit_load_volatile_arguments(MonoCompile
*cfg
, guint8
*code
)
2946 MonoMethod
*method
= cfg
->method
;
2947 MonoMethodSignature
*sig
;
2952 sig
= mono_method_signature (method
);
2953 cinfo
= calculate_sizes (sig
, sig
->pinvoke
);
2954 if (cinfo
->struct_ret
) {
2955 ArgInfo
*ainfo
= &cinfo
->ret
;
2956 inst
= cfg
->vret_addr
;
2957 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
2960 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
2961 ArgInfo
*ainfo
= cinfo
->args
+ i
;
2962 inst
= cfg
->args
[i
];
2963 if (inst
->opcode
== OP_REGVAR
) {
2964 if (ainfo
->regtype
== RegTypeGeneral
)
2965 MIPS_MOVE (code
, ainfo
->reg
, inst
->dreg
);
2966 else if (ainfo
->regtype
== RegTypeFP
)
2967 g_assert_not_reached();
2968 else if (ainfo
->regtype
== RegTypeBase
) {
2971 g_assert_not_reached ();
2973 if (ainfo
->regtype
== RegTypeGeneral
) {
2974 g_assert (mips_is_imm16 (inst
->inst_offset
));
2975 switch (ainfo
->size
) {
2977 mips_lb (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
2980 mips_lh (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
2984 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
2987 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
2988 mips_lw (code
, ainfo
->reg
+ 1, inst
->inst_basereg
, inst
->inst_offset
+ 4);
2991 g_assert_not_reached ();
2994 } else if (ainfo
->regtype
== RegTypeBase
) {
2996 } else if (ainfo
->regtype
== RegTypeFP
) {
2997 g_assert (mips_is_imm16 (inst
->inst_offset
));
2998 if (ainfo
->size
== 8) {
2999 #if _MIPS_SIM == _ABIO32
3000 mips_lwc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+4);
3001 mips_lwc1 (code
, ainfo
->reg
+1, inst
->inst_basereg
, inst
->inst_offset
);
3002 #elif _MIPS_SIM == _ABIN32
3003 mips_ldc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3006 else if (ainfo
->size
== 4)
3007 mips_lwc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3009 g_assert_not_reached ();
3010 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
3012 int doffset
= inst
->inst_offset
;
3014 g_assert (mips_is_imm16 (inst
->inst_offset
));
3015 g_assert (mips_is_imm16 (inst
->inst_offset
+ ainfo
->size
* sizeof (gpointer
)));
3016 for (i
= 0; i
< ainfo
->size
; ++i
) {
3017 mips_lw (code
, ainfo
->reg
+ i
, inst
->inst_basereg
, doffset
);
3018 doffset
+= SIZEOF_REGISTER
;
3020 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
3021 g_assert (mips_is_imm16 (inst
->inst_offset
));
3022 mips_lw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
3024 g_assert_not_reached ();
3034 emit_reserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3036 int size
= cfg
->param_area
;
3038 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3039 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3044 ppc_lwz (code
, ppc_r0
, 0, ppc_sp
);
3045 if (ppc_is_imm16 (-size
)) {
3046 ppc_stwu (code
, ppc_r0
, -size
, ppc_sp
);
3048 ppc_load (code
, ppc_r11
, -size
);
3049 ppc_stwux (code
, ppc_r0
, ppc_sp
, ppc_r11
);
3056 emit_unreserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3058 int size
= cfg
->param_area
;
3060 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3061 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3066 ppc_lwz (code
, ppc_r0
, 0, ppc_sp
);
3067 if (ppc_is_imm16 (size
)) {
3068 ppc_stwu (code
, ppc_r0
, size
, ppc_sp
);
3070 ppc_load (code
, ppc_r11
, size
);
3071 ppc_stwux (code
, ppc_r0
, ppc_sp
, ppc_r11
);
3078 mono_arch_output_basic_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
3083 guint8
*code
= cfg
->native_code
+ cfg
->code_len
;
3084 MonoInst
*last_ins
= NULL
;
3085 guint last_offset
= 0;
3089 /* we don't align basic blocks of loops on mips */
3091 if (cfg
->verbose_level
> 2)
3092 g_print ("Basic block %d starting at offset 0x%x\n", bb
->block_num
, bb
->native_offset
);
3094 cpos
= bb
->max_offset
;
3097 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
) {
3098 MonoCoverageInfo
*cov
= mono_get_coverage_info (cfg
->method
);
3099 g_assert (!mono_compile_aot
);
3102 cov
->data
[bb
->dfn
].iloffset
= bb
->cil_code
- cfg
->cil_code
;
3103 /* this is not thread save, but good enough */
3104 /* fixme: howto handle overflows? */
3105 mips_load_const (code
, mips_at
, &cov
->data
[bb
->dfn
].count
);
3106 mips_lw (code
, mips_temp
, mips_at
, 0);
3107 mips_addiu (code
, mips_temp
, mips_temp
, 1);
3108 mips_sw (code
, mips_temp
, mips_at
, 0);
3111 MONO_BB_FOR_EACH_INS (bb
, ins
) {
3112 offset
= code
- cfg
->native_code
;
3114 max_len
= ((guint8
*)ins_get_spec (ins
->opcode
))[MONO_INST_LEN
];
3116 if (offset
> (cfg
->code_size
- max_len
- 16)) {
3117 cfg
->code_size
*= 2;
3118 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
3119 code
= cfg
->native_code
+ offset
;
3121 mono_debug_record_line_number (cfg
, ins
, offset
);
3122 if (cfg
->verbose_level
> 2) {
3123 g_print (" @ 0x%x\t", offset
);
3124 mono_print_ins_index (ins_cnt
++, ins
);
3126 /* Check for virtual regs that snuck by */
3127 g_assert ((ins
->dreg
>= -1) && (ins
->dreg
< 32));
3129 switch (ins
->opcode
) {
3130 case OP_RELAXED_NOP
:
3133 case OP_DUMMY_STORE
:
3134 case OP_NOT_REACHED
:
3138 g_assert_not_reached();
3140 emit_tls_access (code
, ins
->dreg
, ins
->inst_offset
);
3144 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3145 mips_mflo (code
, ins
->dreg
);
3146 mips_mfhi (code
, ins
->dreg
+1);
3149 mips_multu (code
, ins
->sreg1
, ins
->sreg2
);
3150 mips_mflo (code
, ins
->dreg
);
3151 mips_mfhi (code
, ins
->dreg
+1);
3153 case OP_MEMORY_BARRIER
:
3158 case OP_STOREI1_MEMBASE_IMM
:
3159 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3160 if (mips_is_imm16 (ins
->inst_offset
)) {
3161 mips_sb (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3163 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3164 mips_sb (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3167 case OP_STOREI2_MEMBASE_IMM
:
3168 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3169 if (mips_is_imm16 (ins
->inst_offset
)) {
3170 mips_sh (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3172 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3173 mips_sh (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3176 case OP_STOREI8_MEMBASE_IMM
:
3177 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3178 if (mips_is_imm16 (ins
->inst_offset
)) {
3179 mips_sd (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3181 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3182 mips_sd (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3185 case OP_STORE_MEMBASE_IMM
:
3186 case OP_STOREI4_MEMBASE_IMM
:
3187 mips_load_const (code
, mips_temp
, ins
->inst_imm
);
3188 if (mips_is_imm16 (ins
->inst_offset
)) {
3189 mips_sw (code
, mips_temp
, ins
->inst_destbasereg
, ins
->inst_offset
);
3191 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3192 mips_sw (code
, mips_temp
, mips_at
, ins
->inst_destbasereg
);
3195 case OP_STOREI1_MEMBASE_REG
:
3196 if (mips_is_imm16 (ins
->inst_offset
)) {
3197 mips_sb (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3199 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3200 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3201 mips_sb (code
, ins
->sreg1
, mips_at
, 0);
3204 case OP_STOREI2_MEMBASE_REG
:
3205 if (mips_is_imm16 (ins
->inst_offset
)) {
3206 mips_sh (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3208 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3209 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3210 mips_sh (code
, ins
->sreg1
, mips_at
, 0);
3213 case OP_STORE_MEMBASE_REG
:
3214 case OP_STOREI4_MEMBASE_REG
:
3215 if (mips_is_imm16 (ins
->inst_offset
)) {
3216 mips_sw (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3218 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3219 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3220 mips_sw (code
, ins
->sreg1
, mips_at
, 0);
3223 case OP_STOREI8_MEMBASE_REG
:
3224 if (mips_is_imm16 (ins
->inst_offset
)) {
3225 mips_sd (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3227 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3228 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
3229 mips_sd (code
, ins
->sreg1
, mips_at
, 0);
3233 g_assert_not_reached ();
3234 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3235 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3237 case OP_LOADI8_MEMBASE
:
3238 if (mips_is_imm16 (ins
->inst_offset
)) {
3239 mips_ld (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3241 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3242 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3243 mips_ld (code
, ins
->dreg
, mips_at
, 0);
3246 case OP_LOAD_MEMBASE
:
3247 case OP_LOADI4_MEMBASE
:
3248 case OP_LOADU4_MEMBASE
:
3249 if (mips_is_imm16 (ins
->inst_offset
)) {
3250 mips_lw (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3252 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3253 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3254 mips_lw (code
, ins
->dreg
, mips_at
, 0);
3257 case OP_LOADI1_MEMBASE
:
3258 if (mips_is_imm16 (ins
->inst_offset
)) {
3259 mips_lb (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3261 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3262 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3263 mips_lb (code
, ins
->dreg
, mips_at
, 0);
3266 case OP_LOADU1_MEMBASE
:
3267 if (mips_is_imm16 (ins
->inst_offset
)) {
3268 mips_lbu (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3270 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3271 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3272 mips_lbu (code
, ins
->dreg
, mips_at
, 0);
3275 case OP_LOADI2_MEMBASE
:
3276 if (mips_is_imm16 (ins
->inst_offset
)) {
3277 mips_lh (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3279 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3280 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3281 mips_lh (code
, ins
->dreg
, mips_at
, 0);
3284 case OP_LOADU2_MEMBASE
:
3285 if (mips_is_imm16 (ins
->inst_offset
)) {
3286 mips_lhu (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
3288 mips_load_const (code
, mips_at
, ins
->inst_offset
);
3289 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
3290 mips_lhu (code
, ins
->dreg
, mips_at
, 0);
3293 case OP_ICONV_TO_I1
:
3294 mips_sll (code
, mips_at
, ins
->sreg1
, 24);
3295 mips_sra (code
, ins
->dreg
, mips_at
, 24);
3297 case OP_ICONV_TO_I2
:
3298 mips_sll (code
, mips_at
, ins
->sreg1
, 16);
3299 mips_sra (code
, ins
->dreg
, mips_at
, 16);
3301 case OP_ICONV_TO_U1
:
3302 mips_andi (code
, ins
->dreg
, ins
->sreg1
, 0xff);
3304 case OP_ICONV_TO_U2
:
3305 mips_sll (code
, mips_at
, ins
->sreg1
, 16);
3306 mips_srl (code
, ins
->dreg
, mips_at
, 16);
3309 mips_slt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3312 g_assert (mips_is_imm16 (ins
->inst_imm
));
3313 mips_slti (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3316 mips_sltu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3319 g_assert (mips_is_imm16 (ins
->inst_imm
));
3320 mips_sltiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3323 mips_break (code
, 0xfd);
3326 mips_addu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3329 mips_daddu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3334 g_assert (mips_is_imm16 (ins
->inst_imm
));
3335 mips_addiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3338 g_assert (mips_is_imm16 (ins
->inst_imm
));
3339 mips_daddiu (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3343 mips_subu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3346 mips_dsubu (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3351 // we add the negated value
3352 g_assert (mips_is_imm16 (-ins
->inst_imm
));
3353 mips_addiu (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
3357 // we add the negated value
3358 g_assert (mips_is_imm16 (-ins
->inst_imm
));
3359 mips_daddiu (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
3364 mips_and (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3370 g_assert (!(ins
->inst_imm
& 0xffff0000));
3371 mips_andi (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3376 guint32
*divisor_is_m1
;
3377 guint32
*divisor_is_zero
;
3380 mips_addiu (code
, mips_at
, mips_zero
, 0xffff);
3381 divisor_is_m1
= (guint32
*)(void *)code
;
3382 mips_bne (code
, ins
->sreg2
, mips_at
, 0);
3385 /* Divide by -1 -- throw exception */
3386 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
3388 mips_patch (divisor_is_m1
, (guint32
)code
);
3390 /* Put divide in branch delay slot (NOT YET) */
3391 divisor_is_zero
= (guint32
*)(void *)code
;
3392 mips_bne (code
, ins
->sreg2
, mips_zero
, 0);
3395 /* Divide by zero -- throw exception */
3396 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3398 mips_patch (divisor_is_zero
, (guint32
)code
);
3399 mips_div (code
, ins
->sreg1
, ins
->sreg2
);
3400 if (ins
->opcode
== OP_IDIV
)
3401 mips_mflo (code
, ins
->dreg
);
3403 mips_mfhi (code
, ins
->dreg
);
3408 guint32
*divisor_is_zero
= (guint32
*)(void *)code
;
3410 /* Put divide in branch delay slot (NOT YET) */
3411 mips_bne (code
, ins
->sreg2
, mips_zero
, 0);
3414 /* Divide by zero -- throw exception */
3415 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3417 mips_patch (divisor_is_zero
, (guint32
)code
);
3418 mips_divu (code
, ins
->sreg1
, ins
->sreg2
);
3419 if (ins
->opcode
== OP_IDIV_UN
)
3420 mips_mflo (code
, ins
->dreg
);
3422 mips_mfhi (code
, ins
->dreg
);
3426 g_assert_not_reached ();
3428 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
3429 ppc_divwod (code
, ins
->dreg
, ins
->sreg1
, ppc_r11
);
3430 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3431 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3432 /* FIXME: use OverflowException for 0x80000000/-1 */
3433 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
3435 g_assert_not_reached();
3438 g_assert_not_reached ();
3440 mips_or (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3444 g_assert (!(ins
->inst_imm
& 0xffff0000));
3445 mips_ori (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3448 mips_xor (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3452 /* unsigned 16-bit immediate */
3453 g_assert (!(ins
->inst_imm
& 0xffff0000));
3454 mips_xori (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3457 mips_sllv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3461 mips_sll (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3464 mips_srav (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3467 mips_dsrav (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3471 mips_sra (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3474 mips_dsra (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x3f);
3477 case OP_ISHR_UN_IMM
:
3478 mips_srl (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x1f);
3480 case OP_LSHR_UN_IMM
:
3481 mips_dsrl (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
& 0x3f);
3484 mips_srlv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3487 mips_dsrlv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3491 mips_nor (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3494 mips_subu (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3497 mips_dsubu (code
, ins
->dreg
, mips_zero
, ins
->sreg1
);
3501 mips_mul (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3503 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3504 mips_mflo (code
, ins
->dreg
);
3509 #if SIZEOF_REGISTER == 8
3511 mips_dmult (code
, ins
->sreg1
, ins
->sreg2
);
3512 mips_mflo (code
, ins
->dreg
);
3517 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3518 mips_mflo (code
, ins
->dreg
);
3519 mips_mfhi (code
, mips_at
);
3522 mips_sra (code
, mips_temp
, ins
->dreg
, 31);
3523 patch
= (guint32
*)(void *)code
;
3524 mips_beq (code
, mips_temp
, mips_at
, 0);
3526 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3527 mips_patch (patch
, (guint32
)code
);
3530 case OP_IMUL_OVF_UN
:
3532 mips_mul (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3534 mips_mult (code
, ins
->sreg1
, ins
->sreg2
);
3535 mips_mflo (code
, ins
->dreg
);
3536 mips_mfhi (code
, mips_at
);
3540 /* XXX - Throw exception if we overflowed */
3543 mips_load_const (code
, ins
->dreg
, ins
->inst_c0
);
3545 #if SIZEOF_REGISTER == 8
3547 mips_load_const (code
, ins
->dreg
, ins
->inst_c0
);
3551 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_i1
, ins
->inst_p0
);
3552 mips_load (code
, ins
->dreg
, 0);
3556 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3558 case OP_MIPS_MTC1S_2
:
3559 mips_mtc1 (code
, ins
->dreg
, ins
->sreg1
);
3560 mips_mtc1 (code
, ins
->dreg
+1, ins
->sreg2
);
3563 mips_mfc1 (code
, ins
->dreg
, ins
->sreg1
);
3566 mips_dmtc1 (code
, ins
->dreg
, ins
->sreg1
);
3570 mips_dmfc1 (code
, ins
->dreg
, ins
->sreg1
);
3572 mips_mfc1 (code
, ins
->dreg
+1, ins
->sreg1
);
3573 mips_mfc1 (code
, ins
->dreg
, ins
->sreg1
+1);
3577 case OP_ICONV_TO_I4
:
3578 case OP_ICONV_TO_U4
:
3580 if (ins
->dreg
!= ins
->sreg1
)
3581 MIPS_MOVE (code
, ins
->dreg
, ins
->sreg1
);
3583 #if SIZEOF_REGISTER == 8
3585 mips_dsll (code
, ins
->dreg
, ins
->sreg1
, 32);
3586 mips_dsrl (code
, ins
->dreg
, ins
->dreg
, 32);
3589 mips_dsll (code
, ins
->dreg
, ins
->sreg1
, 32);
3590 mips_dsra (code
, ins
->dreg
, ins
->dreg
, 32);
3594 /* Get sreg1 into v1, sreg2 into v0 */
3596 if (ins
->sreg1
== mips_v0
) {
3597 if (ins
->sreg1
!= mips_at
)
3598 MIPS_MOVE (code
, mips_at
, ins
->sreg1
);
3599 if (ins
->sreg2
!= mips_v0
)
3600 MIPS_MOVE (code
, mips_v0
, ins
->sreg2
);
3601 MIPS_MOVE (code
, mips_v1
, mips_at
);
3604 if (ins
->sreg2
!= mips_v0
)
3605 MIPS_MOVE (code
, mips_v0
, ins
->sreg2
);
3606 if (ins
->sreg1
!= mips_v1
)
3607 MIPS_MOVE (code
, mips_v1
, ins
->sreg1
);
3611 if (ins
->dreg
!= ins
->sreg1
) {
3612 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
3616 /* Convert from double to float and leave it there */
3617 mips_cvtsd (code
, ins
->dreg
, ins
->sreg1
);
3619 case OP_FCONV_TO_R4
:
3621 mips_cvtsd (code
, ins
->dreg
, ins
->sreg1
);
3623 /* Just a move, no precision change */
3624 if (ins
->dreg
!= ins
->sreg1
) {
3625 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
3630 code
= emit_load_volatile_arguments(cfg
, code
);
3633 * Pop our stack, then jump to specified method (tail-call)
3634 * Keep in sync with mono_arch_emit_epilog
3636 code
= mono_arch_emit_epilog_sub (cfg
, code
);
3638 mono_add_patch_info (cfg
, (guint8
*) code
- cfg
->native_code
,
3639 MONO_PATCH_INFO_METHOD_JUMP
, ins
->inst_p0
);
3641 mips_lui (code
, mips_t9
, mips_zero
, 0);
3642 mips_addiu (code
, mips_t9
, mips_t9
, 0);
3643 mips_jr (code
, mips_t9
);
3646 mips_beq (code
, mips_zero
, mips_zero
, 0);
3651 /* ensure ins->sreg1 is not NULL */
3652 mips_lw (code
, mips_zero
, ins
->sreg1
, 0);
3655 if (mips_is_imm16 (cfg
->sig_cookie
+ cfg
->stack_usage
)) {
3656 mips_addiu (code
, mips_at
, cfg
->frame_reg
, cfg
->sig_cookie
+ cfg
->stack_usage
);
3658 mips_load_const (code
, mips_at
, cfg
->sig_cookie
+ cfg
->stack_usage
);
3659 mips_addu (code
, mips_at
, cfg
->frame_reg
, mips_at
);
3661 mips_sw (code
, mips_at
, ins
->sreg1
, 0);
3674 case OP_VOIDCALL_REG
:
3676 case OP_FCALL_MEMBASE
:
3677 case OP_LCALL_MEMBASE
:
3678 case OP_VCALL_MEMBASE
:
3679 case OP_VCALL2_MEMBASE
:
3680 case OP_VOIDCALL_MEMBASE
:
3681 case OP_CALL_MEMBASE
:
3682 call
= (MonoCallInst
*)ins
;
3683 switch (ins
->opcode
) {
3690 if (ins
->flags
& MONO_INST_HAS_METHOD
)
3691 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_METHOD
, call
->method
);
3693 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_ABS
, call
->fptr
);
3694 mips_lui (code
, mips_t9
, mips_zero
, 0);
3695 mips_addiu (code
, mips_t9
, mips_t9
, 0);
3701 case OP_VOIDCALL_REG
:
3703 MIPS_MOVE (code
, mips_t9
, ins
->sreg1
);
3705 case OP_FCALL_MEMBASE
:
3706 case OP_LCALL_MEMBASE
:
3707 case OP_VCALL_MEMBASE
:
3708 case OP_VCALL2_MEMBASE
:
3709 case OP_VOIDCALL_MEMBASE
:
3710 case OP_CALL_MEMBASE
:
3711 mips_lw (code
, mips_t9
, ins
->sreg1
, ins
->inst_offset
);
3714 mips_jalr (code
, mips_t9
, mips_ra
);
3716 #if PROMOTE_R4_TO_R8
3717 /* returned an FP R4 (single), promote to R8 (double) in place */
3718 if ((ins
->opcode
== OP_FCALL
||
3719 ins
->opcode
== OP_FCALL_REG
) &&
3720 call
->signature
->ret
->type
== MONO_TYPE_R4
) {
3721 mips_cvtds (code
, mips_f0
, mips_f0
);
3726 int area_offset
= cfg
->param_area
;
3728 /* Round up ins->sreg1, mips_at ends up holding size */
3729 mips_addiu (code
, mips_at
, ins
->sreg1
, 31);
3730 mips_addiu (code
, mips_temp
, mips_zero
, ~31);
3731 mips_and (code
, mips_at
, mips_at
, mips_temp
);
3733 mips_subu (code
, mips_sp
, mips_sp
, mips_at
);
3734 g_assert (mips_is_imm16 (area_offset
));
3735 mips_addiu (code
, ins
->dreg
, mips_sp
, area_offset
);
3737 if (ins
->flags
& MONO_INST_INIT
) {
3738 mips_move (code
, mips_temp
, ins
->dreg
);
3739 mips_sb (code
, mips_zero
, mips_temp
, 0);
3740 mips_addiu (code
, mips_at
, mips_at
, -1);
3741 mips_bne (code
, mips_at
, mips_zero
, -3);
3742 mips_addiu (code
, mips_temp
, mips_temp
, 1);
3747 gpointer addr
= mono_arch_get_throw_exception();
3748 mips_move (code
, mips_a0
, ins
->sreg1
);
3749 mips_load_const (code
, mips_t9
, addr
);
3750 mips_jalr (code
, mips_t9
, mips_ra
);
3752 mips_break (code
, 0xfc);
3756 gpointer addr
= mono_arch_get_rethrow_exception();
3757 mips_move (code
, mips_a0
, ins
->sreg1
);
3758 mips_load_const (code
, mips_t9
, addr
);
3759 mips_jalr (code
, mips_t9
, mips_ra
);
3761 mips_break (code
, 0xfb);
3764 case OP_START_HANDLER
: {
3766 * The START_HANDLER instruction marks the beginning of
3767 * a handler block. It is called using a call
3768 * instruction, so mips_ra contains the return address.
3769 * Since the handler executes in the same stack frame
3770 * as the method itself, we can't use save/restore to
3771 * save the return address. Instead, we save it into
3772 * a dedicated variable.
3774 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3775 g_assert (spvar
->inst_basereg
!= mips_sp
);
3776 code
= emit_reserve_param_area (cfg
, code
);
3778 if (mips_is_imm16 (spvar
->inst_offset
)) {
3779 mips_sw (code
, mips_ra
, spvar
->inst_basereg
, spvar
->inst_offset
);
3781 mips_load_const (code
, mips_at
, spvar
->inst_offset
);
3782 mips_addu (code
, mips_at
, mips_at
, spvar
->inst_basereg
);
3783 mips_sw (code
, mips_ra
, mips_at
, 0);
3787 case OP_ENDFILTER
: {
3788 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3789 g_assert (spvar
->inst_basereg
!= mips_sp
);
3790 code
= emit_unreserve_param_area (cfg
, code
);
3792 if (ins
->sreg1
!= mips_v0
)
3793 MIPS_MOVE (code
, mips_v0
, ins
->sreg1
);
3794 if (mips_is_imm16 (spvar
->inst_offset
)) {
3795 mips_lw (code
, mips_ra
, spvar
->inst_basereg
, spvar
->inst_offset
);
3797 mips_load_const (code
, mips_at
, spvar
->inst_offset
);
3798 mips_addu (code
, mips_at
, mips_at
, spvar
->inst_basereg
);
3799 mips_lw (code
, mips_ra
, mips_at
, 0);
3801 mips_jr (code
, mips_ra
);
3805 case OP_ENDFINALLY
: {
3806 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3807 g_assert (spvar
->inst_basereg
!= mips_sp
);
3808 code
= emit_unreserve_param_area (cfg
, code
);
3809 mips_lw (code
, mips_t9
, spvar
->inst_basereg
, spvar
->inst_offset
);
3810 mips_jalr (code
, mips_t9
, mips_ra
);
3814 case OP_CALL_HANDLER
:
3815 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
3816 mips_lui (code
, mips_t9
, mips_zero
, 0);
3817 mips_addiu (code
, mips_t9
, mips_t9
, 0);
3818 mips_jalr (code
, mips_t9
, mips_ra
);
3822 ins
->inst_c0
= code
- cfg
->native_code
;
3825 if (ins
->flags
& MONO_INST_BRLABEL
) {
3826 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
3828 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
3831 mips_lui (code
, mips_at
, mips_zero
, 0);
3832 mips_addiu (code
, mips_at
, mips_at
, 0);
3833 mips_jr (code
, mips_at
);
3836 mips_beq (code
, mips_zero
, mips_zero
, 0);
3841 mips_jr (code
, ins
->sreg1
);
3847 max_len
+= 4 * GPOINTER_TO_INT (ins
->klass
);
3848 if (offset
> (cfg
->code_size
- max_len
- 16)) {
3849 cfg
->code_size
+= max_len
;
3850 cfg
->code_size
*= 2;
3851 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
3852 code
= cfg
->native_code
+ offset
;
3854 g_assert (ins
->sreg1
!= -1);
3855 mips_sll (code
, mips_at
, ins
->sreg1
, 2);
3856 if (1 || !(cfg
->flags
& MONO_CFG_HAS_CALLS
))
3857 MIPS_MOVE (code
, mips_t8
, mips_ra
);
3858 mips_bgezal (code
, mips_zero
, 1); /* bal */
3860 mips_addu (code
, mips_t9
, mips_ra
, mips_at
);
3861 /* Table is 16 or 20 bytes from target of bal above */
3862 if (1 || !(cfg
->flags
& MONO_CFG_HAS_CALLS
)) {
3863 MIPS_MOVE (code
, mips_ra
, mips_t8
);
3864 mips_lw (code
, mips_t9
, mips_t9
, 20);
3867 mips_lw (code
, mips_t9
, mips_t9
, 16);
3868 mips_jalr (code
, mips_t9
, mips_t8
);
3870 for (i
= 0; i
< GPOINTER_TO_INT (ins
->klass
); ++i
)
3871 mips_emit32 (code
, 0xfefefefe);
3876 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
3877 mips_beq (code
, mips_at
, mips_zero
, 2);
3879 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
3885 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
3886 mips_bltz (code
, mips_at
, 2);
3888 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
3894 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
3895 mips_bgtz (code
, mips_at
, 2);
3897 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
3900 case OP_MIPS_COND_EXC_EQ
:
3901 case OP_MIPS_COND_EXC_GE
:
3902 case OP_MIPS_COND_EXC_GT
:
3903 case OP_MIPS_COND_EXC_LE
:
3904 case OP_MIPS_COND_EXC_LT
:
3905 case OP_MIPS_COND_EXC_NE_UN
:
3906 case OP_MIPS_COND_EXC_GE_UN
:
3907 case OP_MIPS_COND_EXC_GT_UN
:
3908 case OP_MIPS_COND_EXC_LE_UN
:
3909 case OP_MIPS_COND_EXC_LT_UN
:
3911 case OP_MIPS_COND_EXC_OV
:
3912 case OP_MIPS_COND_EXC_NO
:
3913 case OP_MIPS_COND_EXC_C
:
3914 case OP_MIPS_COND_EXC_NC
:
3916 case OP_MIPS_COND_EXC_IEQ
:
3917 case OP_MIPS_COND_EXC_IGE
:
3918 case OP_MIPS_COND_EXC_IGT
:
3919 case OP_MIPS_COND_EXC_ILE
:
3920 case OP_MIPS_COND_EXC_ILT
:
3921 case OP_MIPS_COND_EXC_INE_UN
:
3922 case OP_MIPS_COND_EXC_IGE_UN
:
3923 case OP_MIPS_COND_EXC_IGT_UN
:
3924 case OP_MIPS_COND_EXC_ILE_UN
:
3925 case OP_MIPS_COND_EXC_ILT_UN
:
3927 case OP_MIPS_COND_EXC_IOV
:
3928 case OP_MIPS_COND_EXC_INO
:
3929 case OP_MIPS_COND_EXC_IC
:
3930 case OP_MIPS_COND_EXC_INC
: {
3934 /* If the condition is true, raise the exception */
3936 /* need to reverse test to skip around exception raising */
3938 /* For the moment, branch around a branch to avoid reversing
3941 /* Remember, an unpatched branch to 0 branches to the delay slot */
3942 switch (ins
->opcode
) {
3943 case OP_MIPS_COND_EXC_EQ
:
3944 throw = (guint32
*)(void *)code
;
3945 mips_beq (code
, ins
->sreg1
, ins
->sreg2
, 0);
3949 case OP_MIPS_COND_EXC_NE_UN
:
3950 throw = (guint32
*)(void *)code
;
3951 mips_bne (code
, ins
->sreg1
, ins
->sreg2
, 0);
3955 case OP_MIPS_COND_EXC_LE_UN
:
3956 mips_subu (code
, mips_at
, ins
->sreg1
, ins
->sreg2
);
3957 throw = (guint32
*)(void *)code
;
3958 mips_blez (code
, mips_at
, 0);
3962 case OP_MIPS_COND_EXC_GT
:
3963 mips_slt (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
3964 throw = (guint32
*)(void *)code
;
3965 mips_bne (code
, mips_at
, mips_zero
, 0);
3969 case OP_MIPS_COND_EXC_GT_UN
:
3970 mips_sltu (code
, mips_at
, ins
->sreg2
, ins
->sreg1
);
3971 throw = (guint32
*)(void *)code
;
3972 mips_bne (code
, mips_at
, mips_zero
, 0);
3976 case OP_MIPS_COND_EXC_LT
:
3977 mips_slt (code
, mips_at
, ins
->sreg1
, ins
->sreg2
);
3978 throw = (guint32
*)(void *)code
;
3979 mips_bne (code
, mips_at
, mips_zero
, 0);
3983 case OP_MIPS_COND_EXC_LT_UN
:
3984 mips_sltu (code
, mips_at
, ins
->sreg1
, ins
->sreg2
);
3985 throw = (guint32
*)(void *)code
;
3986 mips_bne (code
, mips_at
, mips_zero
, 0);
3991 /* Not yet implemented */
3992 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins
->opcode
));
3993 g_assert_not_reached ();
3995 skip
= (guint32
*)(void *)code
;
3996 mips_beq (code
, mips_zero
, mips_zero
, 0);
3998 mips_patch (throw, (guint32
)code
);
3999 code
= mips_emit_exc_by_name (code
, ins
->inst_p1
);
4000 mips_patch (skip
, (guint32
)code
);
4001 cfg
->bb_exit
->max_offset
+= 24;
4010 code
= mips_emit_cond_branch (cfg
, code
, ins
->opcode
, ins
);
4013 /* floating point opcodes */
4016 if (((guint32
)ins
->inst_p0
) & (1 << 15))
4017 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16)+1);
4019 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16));
4020 mips_ldc1 (code
, ins
->dreg
, mips_at
, ((guint32
)ins
->inst_p0
) & 0xffff);
4022 mips_load_const (code
, mips_at
, ins
->inst_p0
);
4023 mips_lwc1 (code
, ins
->dreg
, mips_at
, 4);
4024 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, 0);
4028 if (((guint32
)ins
->inst_p0
) & (1 << 15))
4029 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16)+1);
4031 mips_lui (code
, mips_at
, mips_zero
, (((guint32
)ins
->inst_p0
)>>16));
4032 mips_lwc1 (code
, ins
->dreg
, mips_at
, ((guint32
)ins
->inst_p0
) & 0xffff);
4033 #if PROMOTE_R4_TO_R8
4034 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4037 case OP_STORER8_MEMBASE_REG
:
4038 if (mips_is_imm16 (ins
->inst_offset
)) {
4039 #if _MIPS_SIM == _ABIO32
4040 mips_swc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
+4);
4041 mips_swc1 (code
, ins
->sreg1
+1, ins
->inst_destbasereg
, ins
->inst_offset
);
4042 #elif _MIPS_SIM == _ABIN32
4043 mips_sdc1 (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
4046 mips_load_const (code
, mips_at
, ins
->inst_offset
);
4047 mips_addu (code
, mips_at
, mips_at
, ins
->inst_destbasereg
);
4048 mips_swc1 (code
, ins
->sreg1
, mips_at
, 4);
4049 mips_swc1 (code
, ins
->sreg1
+1, mips_at
, 0);
4052 case OP_LOADR8_MEMBASE
:
4053 if (mips_is_imm16 (ins
->inst_offset
)) {
4054 #if _MIPS_SIM == _ABIO32
4055 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
+4);
4056 mips_lwc1 (code
, ins
->dreg
+1, ins
->inst_basereg
, ins
->inst_offset
);
4057 #elif _MIPS_SIM == _ABIN32
4058 mips_ldc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4061 mips_load_const (code
, mips_at
, ins
->inst_offset
);
4062 mips_addu (code
, mips_at
, mips_at
, ins
->inst_basereg
);
4063 mips_lwc1 (code
, ins
->dreg
, mips_at
, 4);
4064 mips_lwc1 (code
, ins
->dreg
+1, mips_at
, 0);
4067 case OP_STORER4_MEMBASE_REG
:
4068 g_assert (mips_is_imm16 (ins
->inst_offset
));
4069 #if PROMOTE_R4_TO_R8
4070 /* Need to convert ins->sreg1 to single-precision first */
4071 mips_cvtsd (code
, mips_ftemp
, ins
->sreg1
);
4073 mips_swc1 (code
, mips_ftemp
, ins
->inst_destbasereg
, ins
->inst_offset
);
4076 g_assert (mips_is_imm16 (ins
->inst_offset
));
4077 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4079 case OP_LOADR4_MEMBASE
:
4080 g_assert (mips_is_imm16 (ins
->inst_offset
));
4081 mips_lwc1 (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
4082 #if PROMOTE_R4_TO_R8
4083 /* Convert to double precision in place */
4084 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4087 case OP_ICONV_TO_R_UN
: {
4088 static const guint64 adjust_val
= 0x41F0000000000000ULL
;
4090 /* convert unsigned int to double */
4091 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4092 mips_bgez (code
, ins
->sreg1
, 5);
4093 mips_cvtdw (code
, ins
->dreg
, mips_ftemp
);
4095 mips_load (code
, mips_at
, (guint32
) &adjust_val
);
4096 mips_ldc1 (code
, mips_ftemp
, mips_at
, 0);
4097 mips_faddd (code
, ins
->dreg
, ins
->dreg
, mips_ftemp
);
4098 /* target is here */
4101 case OP_ICONV_TO_R4
:
4102 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4103 mips_cvtsw (code
, ins
->dreg
, mips_ftemp
);
4104 mips_cvtds (code
, ins
->dreg
, ins
->dreg
);
4106 case OP_ICONV_TO_R8
:
4107 mips_mtc1 (code
, mips_ftemp
, ins
->sreg1
);
4108 mips_cvtdw (code
, ins
->dreg
, mips_ftemp
);
4110 case OP_FCONV_TO_I1
:
4111 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, TRUE
);
4113 case OP_FCONV_TO_U1
:
4114 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, FALSE
);
4116 case OP_FCONV_TO_I2
:
4117 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, TRUE
);
4119 case OP_FCONV_TO_U2
:
4120 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, FALSE
);
4122 case OP_FCONV_TO_I4
:
4124 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, TRUE
);
4126 case OP_FCONV_TO_U4
:
4128 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, FALSE
);
4131 mips_fsqrtd (code
, ins
->dreg
, ins
->sreg1
);
4134 mips_faddd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4137 mips_fsubd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4140 mips_fmuld (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4143 mips_fdivd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4146 mips_fnegd (code
, ins
->dreg
, ins
->sreg1
);
4149 mips_fcmpd (code
, MIPS_FPU_EQ
, ins
->sreg1
, ins
->sreg2
);
4150 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4151 mips_fbtrue (code
, 2);
4153 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4156 mips_fcmpd (code
, MIPS_FPU_LT
, ins
->sreg1
, ins
->sreg2
);
4157 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4158 mips_fbtrue (code
, 2);
4160 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4163 /* Less than, or Unordered */
4164 mips_fcmpd (code
, MIPS_FPU_ULT
, ins
->sreg1
, ins
->sreg2
);
4165 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4166 mips_fbtrue (code
, 2);
4168 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4171 mips_fcmpd (code
, MIPS_FPU_ULE
, ins
->sreg1
, ins
->sreg2
);
4172 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4173 mips_fbtrue (code
, 2);
4175 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4178 /* Greater than, or Unordered */
4179 mips_fcmpd (code
, MIPS_FPU_OLE
, ins
->sreg1
, ins
->sreg2
);
4180 MIPS_MOVE (code
, ins
->dreg
, mips_zero
);
4181 mips_fbtrue (code
, 2);
4183 mips_addiu (code
, ins
->dreg
, mips_zero
, 1);
4186 mips_fcmpd (code
, MIPS_FPU_EQ
, ins
->sreg1
, ins
->sreg2
);
4188 if (ins
->flags
& MONO_INST_BRLABEL
)
4189 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
4191 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4192 mips_fbtrue (code
, 0);
4196 mips_fcmpd (code
, MIPS_FPU_EQ
, ins
->sreg1
, ins
->sreg2
);
4198 if (ins
->flags
& MONO_INST_BRLABEL
)
4199 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
4201 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4202 mips_fbfalse (code
, 0);
4206 mips_fcmpd (code
, MIPS_FPU_LT
, ins
->sreg1
, ins
->sreg2
);
4208 if (ins
->flags
& MONO_INST_BRLABEL
)
4209 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
4211 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4212 mips_fbtrue (code
, 0);
4215 case OP_MIPS_FBLT_UN
:
4216 mips_fcmpd (code
, MIPS_FPU_ULT
, ins
->sreg1
, ins
->sreg2
);
4218 if (ins
->flags
& MONO_INST_BRLABEL
)
4219 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
4221 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4222 mips_fbtrue (code
, 0);
4226 mips_fcmpd (code
, MIPS_FPU_LE
, ins
->sreg1
, ins
->sreg2
);
4228 if (ins
->flags
& MONO_INST_BRLABEL
)
4229 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
4231 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4232 mips_fbfalse (code
, 0);
4235 case OP_MIPS_FBGT_UN
:
4236 mips_fcmpd (code
, MIPS_FPU_OLE
, ins
->sreg1
, ins
->sreg2
);
4238 if (ins
->flags
& MONO_INST_BRLABEL
)
4239 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
4241 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4242 mips_fbfalse (code
, 0);
4246 mips_fcmpd (code
, MIPS_FPU_LT
, ins
->sreg1
, ins
->sreg2
);
4248 if (ins
->flags
& MONO_INST_BRLABEL
)
4249 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
4251 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4252 mips_fbfalse (code
, 0);
4255 case OP_MIPS_FBGE_UN
:
4256 mips_fcmpd (code
, MIPS_FPU_OLT
, ins
->sreg1
, ins
->sreg2
);
4258 if (ins
->flags
& MONO_INST_BRLABEL
)
4259 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
4261 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4262 mips_fbfalse (code
, 0);
4266 mips_fcmpd (code
, MIPS_FPU_OLE
, ins
->sreg1
, ins
->sreg2
);
4268 if (ins
->flags
& MONO_INST_BRLABEL
)
4269 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
4271 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4272 mips_fbtrue (code
, 0);
4275 case OP_MIPS_FBLE_UN
:
4276 mips_fcmpd (code
, MIPS_FPU_ULE
, ins
->sreg1
, ins
->sreg2
);
4278 if (ins
->flags
& MONO_INST_BRLABEL
)
4279 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
4281 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_true_bb
);
4282 mips_fbtrue (code
, 0);
4286 guint32
*branch_patch
;
4288 mips_mfc1 (code
, mips_at
, ins
->sreg1
+1);
4289 mips_srl (code
, mips_at
, mips_at
, 16+4);
4290 mips_andi (code
, mips_at
, mips_at
, 2047);
4291 mips_addiu (code
, mips_at
, mips_at
, -2047);
4293 branch_patch
= (guint32
*)(void *)code
;
4294 mips_bne (code
, mips_at
, mips_zero
, 0);
4297 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4298 mips_patch (branch_patch
, (guint32
)code
);
4299 mips_fmovd (code
, ins
->dreg
, ins
->sreg1
);
4303 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_c1
, ins
->inst_p0
);
4304 mips_load (code
, ins
->dreg
, 0x0f0f0f0f);
4309 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins
->opcode
), __FUNCTION__
);
4310 g_assert_not_reached ();
4313 if ((cfg
->opt
& MONO_OPT_BRANCH
) && ((code
- cfg
->native_code
- offset
) > max_len
)) {
4314 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4315 mono_inst_name (ins
->opcode
), max_len
, code
- cfg
->native_code
- offset
);
4316 g_assert_not_reached ();
4322 last_offset
= offset
;
4325 cfg
->code_len
= code
- cfg
->native_code
;
4329 mono_arch_register_lowlevel_calls (void)
4334 mono_arch_patch_code (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*ji
, gboolean run_cctors
)
4336 MonoJumpInfo
*patch_info
;
4338 for (patch_info
= ji
; patch_info
; patch_info
= patch_info
->next
) {
4339 unsigned char *ip
= patch_info
->ip
.i
+ code
;
4340 const unsigned char *target
= NULL
;
4342 switch (patch_info
->type
) {
4343 case MONO_PATCH_INFO_IP
:
4344 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)ip
);
4346 case MONO_PATCH_INFO_SWITCH
: {
4347 gpointer
*table
= (gpointer
*)patch_info
->data
.table
->table
;
4350 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)table
);
4352 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
4353 table
[i
] = (int)patch_info
->data
.table
->table
[i
] + code
;
4357 case MONO_PATCH_INFO_METHODCONST
:
4358 case MONO_PATCH_INFO_CLASS
:
4359 case MONO_PATCH_INFO_IMAGE
:
4360 case MONO_PATCH_INFO_FIELD
:
4361 case MONO_PATCH_INFO_VTABLE
:
4362 case MONO_PATCH_INFO_IID
:
4363 case MONO_PATCH_INFO_SFLDA
:
4364 case MONO_PATCH_INFO_LDSTR
:
4365 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
4366 case MONO_PATCH_INFO_LDTOKEN
:
4367 case MONO_PATCH_INFO_R4
:
4368 case MONO_PATCH_INFO_R8
:
4369 /* from OP_AOTCONST : lui + addiu */
4370 target
= mono_resolve_patch_target (method
, domain
, code
, patch_info
, run_cctors
);
4371 patch_lui_addiu ((guint32
*)(void *)ip
, (guint32
)target
);
4374 case MONO_PATCH_INFO_EXC_NAME
:
4375 g_assert_not_reached ();
4376 *((gconstpointer
*)(void *)(ip
+ 1)) = patch_info
->data
.name
;
4379 case MONO_PATCH_INFO_NONE
:
4380 /* everything is dealt with at epilog output time */
4383 target
= mono_resolve_patch_target (method
, domain
, code
, patch_info
, run_cctors
);
4384 mips_patch ((guint32
*)(void *)ip
, (guint32
)target
);
4393 mono_trace_lmf_prolog (MonoLMF
*new_lmf
)
4399 mono_trace_lmf_epilog (MonoLMF
*old_lmf
)
4405 * Allow tracing to work with this interface (with an optional argument)
4407 * This code is expected to be inserted just after the 'real' prolog code,
4408 * and before the first basic block. We need to allocate a 2nd, temporary
4409 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4413 mono_arch_instrument_prolog (MonoCompile
*cfg
, void *func
, void *p
, gboolean enable_arguments
)
4416 int offset
= cfg
->arch
.tracing_offset
;
4422 /* For N32, need to know for each stack slot if it's an integer
4423 * or float argument, and save/restore the appropriate register
4425 MIPS_SW (code
, mips_a0
, mips_sp
, offset
+ 0*SIZEOF_REGISTER
);
4426 MIPS_SW (code
, mips_a1
, mips_sp
, offset
+ 1*SIZEOF_REGISTER
);
4427 MIPS_SW (code
, mips_a2
, mips_sp
, offset
+ 2*SIZEOF_REGISTER
);
4428 MIPS_SW (code
, mips_a3
, mips_sp
, offset
+ 3*SIZEOF_REGISTER
);
4429 #if _MIPS_SIM == _ABIN32
4430 MIPS_SW (code
, mips_a4
, mips_sp
, offset
+ 4*SIZEOF_REGISTER
);
4431 MIPS_SW (code
, mips_a5
, mips_sp
, offset
+ 5*SIZEOF_REGISTER
);
4432 MIPS_SW (code
, mips_a6
, mips_sp
, offset
+ 6*SIZEOF_REGISTER
);
4433 MIPS_SW (code
, mips_a7
, mips_sp
, offset
+ 7*SIZEOF_REGISTER
);
4436 mips_load_const (code
, mips_a0
, cfg
->method
);
4437 mips_addiu (code
, mips_a1
, mips_sp
, offset
);
4438 mips_load_const (code
, mips_t9
, func
);
4439 mips_jalr (code
, mips_t9
, mips_ra
);
4442 MIPS_LW (code
, mips_a0
, mips_sp
, offset
+ 0*SIZEOF_REGISTER
);
4443 MIPS_LW (code
, mips_a1
, mips_sp
, offset
+ 1*SIZEOF_REGISTER
);
4444 MIPS_LW (code
, mips_a2
, mips_sp
, offset
+ 2*SIZEOF_REGISTER
);
4445 MIPS_LW (code
, mips_a3
, mips_sp
, offset
+ 3*SIZEOF_REGISTER
);
4446 #if _MIPS_SIM == _ABIN32
4447 MIPS_LW (code
, mips_a4
, mips_sp
, offset
+ 4*SIZEOF_REGISTER
);
4448 MIPS_LW (code
, mips_a5
, mips_sp
, offset
+ 5*SIZEOF_REGISTER
);
4449 MIPS_LW (code
, mips_a6
, mips_sp
, offset
+ 6*SIZEOF_REGISTER
);
4450 MIPS_LW (code
, mips_a7
, mips_sp
, offset
+ 7*SIZEOF_REGISTER
);
4460 mips_adjust_stackframe(MonoCompile
*cfg
)
4463 int delta
, threshold
, i
;
4464 MonoMethodSignature
*sig
;
4467 if (cfg
->stack_offset
== cfg
->arch
.local_alloc_offset
)
4470 /* adjust cfg->stack_offset for account for down-spilling */
4471 cfg
->stack_offset
+= SIZEOF_REGISTER
;
4473 /* re-align cfg->stack_offset if needed (due to var spilling) */
4474 cfg
->stack_offset
= (cfg
->stack_offset
+ MIPS_STACK_ALIGNMENT
- 1) & ~(MIPS_STACK_ALIGNMENT
- 1);
4475 delta
= cfg
->stack_offset
- cfg
->arch
.local_alloc_offset
;
4476 if (cfg
->verbose_level
> 2) {
4477 g_print ("mips_adjust_stackframe:\n");
4478 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg
->arch
.local_alloc_offset
, cfg
->stack_offset
);
4480 threshold
= cfg
->arch
.local_alloc_offset
;
4481 ra_offset
= cfg
->stack_offset
- sizeof(gpointer
);
4482 if (cfg
->verbose_level
> 2) {
4483 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset
, ra_offset
, delta
, delta
);
4486 sig
= mono_method_signature (cfg
->method
);
4487 if (sig
&& sig
->ret
&& MONO_TYPE_ISSTRUCT (sig
->ret
)) {
4488 cfg
->vret_addr
->inst_offset
+= delta
;
4490 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4491 MonoInst
*inst
= cfg
->args
[i
];
4493 inst
->inst_offset
+= delta
;
4497 * loads and stores based off the frame reg that (used to) lie
4498 * above the spill var area need to be increased by 'delta'
4499 * to make room for the spill vars.
4501 /* Need to find loads and stores to adjust that
4502 * are above where the spillvars were inserted, but
4503 * which are not the spillvar references themselves.
4505 * Idea - since all offsets from fp are positive, make
4506 * spillvar offsets negative to begin with so we can spot
4511 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
4515 if (cfg
->verbose_level
> 2) {
4516 g_print ("BASIC BLOCK %d:\n", bb
->block_num
);
4518 MONO_BB_FOR_EACH_INS (bb
, ins
) {
4522 if (cfg
->verbose_level
> 2) {
4523 mono_print_ins_index (ins_cnt
, ins
);
4525 if (MONO_IS_LOAD_MEMBASE(ins
) && (ins
->inst_basereg
== mips_fp
))
4527 if (MONO_IS_STORE_MEMBASE(ins
) && (ins
->dreg
== mips_fp
))
4529 /* The following two catch FP spills */
4530 if (MONO_IS_LOAD_MEMBASE(ins
) && (ins
->inst_basereg
== mips_sp
))
4532 if (MONO_IS_STORE_MEMBASE(ins
) && (ins
->dreg
== mips_sp
))
4534 if (((ins
->opcode
== OP_ADD_IMM
) || (ins
->opcode
== OP_IADD_IMM
)) && (ins
->sreg1
== mips_fp
))
4537 if (ins
->inst_c0
>= threshold
) {
4538 ins
->inst_c0
+= delta
;
4539 if (cfg
->verbose_level
> 2) {
4541 mono_print_ins_index (ins_cnt
, ins
);
4544 else if (ins
->inst_c0
< 0) {
4545 ins
->inst_c0
= - ins
->inst_c0
- 4;
4546 if (cfg
->verbose_level
> 2) {
4548 mono_print_ins_index (ins_cnt
, ins
);
4551 g_assert (ins
->inst_c0
!= ra_offset
);
4554 if (ins
->inst_imm
>= threshold
) {
4555 ins
->inst_imm
+= delta
;
4556 if (cfg
->verbose_level
> 2) {
4558 mono_print_ins_index (ins_cnt
, ins
);
4561 g_assert (ins
->inst_c0
!= ra_offset
);
4571 * Stack frame layout:
4573 * ------------------- sp + cfg->stack_usage + cfg->param_area
4574 * param area incoming
4575 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4577 * ------------------- sp + cfg->stack_usage
4579 * ------------------- sp + cfg->stack_usage-4
4581 * ------------------- sp +
4582 * MonoLMF structure optional
4583 * ------------------- sp + cfg->arch.lmf_offset
4584 * saved registers s0-s8
4585 * ------------------- sp + cfg->arch.iregs_offset
4587 * ------------------- sp + cfg->param_area
4588 * param area outgoing
4589 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4591 * ------------------- sp
4595 mono_arch_emit_prolog (MonoCompile
*cfg
)
4597 MonoMethod
*method
= cfg
->method
;
4598 MonoMethodSignature
*sig
;
4600 int alloc_size
, pos
, i
;
4604 guint32 iregs_to_save
= 0;
4606 guint32 fregs_to_save
= 0;
4609 /* lmf_offset is the offset of the LMF from our stack pointer. */
4610 guint32 lmf_offset
= cfg
->arch
.lmf_offset
;
4613 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
))
4617 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
4619 sig
= mono_method_signature (method
);
4620 cfg
->code_size
= 768 + sig
->param_count
* 20;
4621 code
= cfg
->native_code
= g_malloc (cfg
->code_size
);
4624 #if _MIPS_SIM == _ABIO32
4625 cfg
->arch
.tracing_offset
= cfg
->stack_offset
;
4626 #elif _MIPS_SIM == _ABIN32
4627 /* no stack slots by default for argument regs, reserve a special block */
4628 cfg
->arch
.tracing_offset
= cfg
->stack_offset
;
4629 cfg
->stack_offset
+= 8 * SIZEOF_REGISTER
;
4633 /* adjust stackframe assignments for spillvars if needed */
4634 mips_adjust_stackframe (cfg
);
4636 /* stack_offset should not be changed here. */
4637 alloc_size
= cfg
->stack_offset
;
4638 cfg
->stack_usage
= alloc_size
;
4641 iregs_to_save
= MONO_ARCH_CALLEE_SAVED_REGS
;
4643 iregs_to_save
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
4647 fregs_to_save
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
4649 fregs_to_save
= MONO_ARCH_CALLEE_SAVED_FREGS
;
4650 fregs_to_save
|= (fregs_to_save
<< 1);
4654 if (mips_is_imm16 (-alloc_size
)) {
4655 mips_addiu (code
, mips_sp
, mips_sp
, -alloc_size
);
4657 mips_load_const (code
, mips_at
, -alloc_size
);
4658 mips_addu (code
, mips_sp
, mips_sp
, mips_at
);
4662 if ((cfg
->flags
& MONO_CFG_HAS_CALLS
) || ALWAYS_SAVE_RA
)
4663 mips_sw (code
, mips_ra
, mips_sp
, alloc_size
+ MIPS_RET_ADDR_OFFSET
);
4665 /* XXX - optimize this later to not save all regs if LMF constructed */
4667 if (iregs_to_save
) {
4668 /* save used registers in own stack frame (at pos) */
4669 pos
= cfg
->arch
.iregs_offset
;
4670 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
4671 if (iregs_to_save
& (1 << i
)) {
4672 g_assert (pos
< cfg
->stack_usage
- sizeof(gpointer
));
4673 MIPS_SW (code
, i
, mips_sp
, pos
);
4674 pos
+= SIZEOF_REGISTER
;
4679 if (method
->save_lmf
) {
4680 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
4681 MIPS_SW (code
, i
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, iregs
[i
]));
4687 /* Save float registers */
4688 if (fregs_to_save
) {
4689 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
4690 if (fregs_to_save
& (1 << i
)) {
4691 g_assert (pos
< cfg
->stack_usage
- MIPS_STACK_ALIGNMENT
);
4692 mips_swc1 (code
, i
, mips_sp
, pos
);
4693 pos
+= sizeof (gulong
);
4698 if (method
->save_lmf
) {
4699 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
4700 mips_swc1 (code
, i
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, fregs
[i
]));
4705 if (cfg
->frame_reg
!= mips_sp
) {
4706 MIPS_MOVE (code
, cfg
->frame_reg
, mips_sp
);
4708 if (method
->save_lmf
)
4709 MIPS_SW (code
, cfg
->frame_reg
, mips_sp
,
4710 lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, iregs
[cfg
->frame_reg
]));
4714 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
4715 * to the t* registers, which would be clobbered by the instrumentation calls.
4718 code
= mono_arch_instrument_prolog (cfg
, mono_trace_enter_method
, code
, TRUE
);
4722 /* load arguments allocated to register from the stack */
4725 cinfo
= calculate_sizes (sig
, sig
->pinvoke
);
4727 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
4728 ArgInfo
*ainfo
= &cinfo
->ret
;
4729 inst
= cfg
->vret_addr
;
4730 if (inst
->opcode
== OP_REGVAR
)
4731 MIPS_MOVE (code
, inst
->dreg
, ainfo
->reg
);
4732 else if (mips_is_imm16 (inst
->inst_offset
)) {
4733 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4735 mips_load_const (code
, mips_at
, inst
->inst_offset
);
4736 mips_addu (code
, mips_at
, mips_at
, inst
->inst_basereg
);
4737 mips_sw (code
, ainfo
->reg
, mips_at
, 0);
4740 /* Keep this in sync with emit_load_volatile_arguments */
4741 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4742 ArgInfo
*ainfo
= cinfo
->args
+ i
;
4743 inst
= cfg
->args
[pos
];
4745 if (cfg
->verbose_level
> 2)
4746 g_print ("Saving argument %d (type: %d)\n", i
, ainfo
->regtype
);
4747 if (inst
->opcode
== OP_REGVAR
) {
4748 /* Argument ends up in a register */
4749 if (ainfo
->regtype
== RegTypeGeneral
)
4750 MIPS_MOVE (code
, inst
->dreg
, ainfo
->reg
);
4751 else if (ainfo
->regtype
== RegTypeFP
) {
4752 g_assert_not_reached();
4754 ppc_fmr (code
, inst
->dreg
, ainfo
->reg
);
4757 else if (ainfo
->regtype
== RegTypeBase
) {
4758 mips_lw (code
, inst
->dreg
, mips_sp
, cfg
->stack_usage
+ ainfo
->offset
);
4760 g_assert_not_reached ();
4762 if (cfg
->verbose_level
> 2)
4763 g_print ("Argument %d assigned to register %s\n", pos
, mono_arch_regname (inst
->dreg
));
4765 /* Argument ends up on the stack */
4766 if (ainfo
->regtype
== RegTypeGeneral
) {
4767 /* Incoming parameters should be above this frame */
4768 if (cfg
->verbose_level
> 2)
4769 g_print ("stack slot at %d of %d\n", inst
->inst_offset
, alloc_size
);
4770 /* g_assert (inst->inst_offset >= alloc_size); */
4771 g_assert (mips_is_imm16 (inst
->inst_offset
));
4772 switch (ainfo
->size
) {
4774 mips_sb (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4777 mips_sh (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4781 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4784 #if (SIZEOF_REGISTER == 4)
4785 mips_sw (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4786 mips_sw (code
, ainfo
->reg
+ 1, inst
->inst_basereg
, inst
->inst_offset
+ 4);
4787 #elif (SIZEOF_REGISTER == 8)
4788 mips_sd (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4792 g_assert_not_reached ();
4795 } else if (ainfo
->regtype
== RegTypeBase
) {
4797 * Argument comes in on the stack, and ends up on the stack
4798 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4799 * 8 and 16 bit quantities. Shorten them in place.
4801 g_assert (mips_is_imm16 (inst
->inst_offset
));
4802 switch (ainfo
->size
) {
4804 mips_lw (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4805 mips_sb (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4808 mips_lw (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4809 mips_sh (code
, mips_at
, inst
->inst_basereg
, inst
->inst_offset
);
4816 g_assert_not_reached ();
4818 } else if (ainfo
->regtype
== RegTypeFP
) {
4819 g_assert (mips_is_imm16 (inst
->inst_offset
));
4820 if (ainfo
->size
== 8) {
4821 #if _MIPS_SIM == _ABIO32
4822 mips_swc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
+4);
4823 mips_swc1 (code
, ainfo
->reg
+1, inst
->inst_basereg
, inst
->inst_offset
);
4824 #elif _MIPS_SIM == _ABIN32
4825 mips_sdc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4828 else if (ainfo
->size
== 4)
4829 mips_swc1 (code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
4831 g_assert_not_reached ();
4832 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
4834 int doffset
= inst
->inst_offset
;
4836 g_assert (mips_is_imm16 (inst
->inst_offset
));
4837 g_assert (mips_is_imm16 (inst
->inst_offset
+ ainfo
->size
* sizeof (gpointer
)));
4838 /* Push the argument registers into their stack slots */
4839 for (i
= 0; i
< ainfo
->size
; ++i
) {
4840 MIPS_SW (code
, ainfo
->reg
+ i
, inst
->inst_basereg
, doffset
);
4841 doffset
+= SIZEOF_REGISTER
;
4843 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
4844 g_assert (mips_is_imm16 (inst
->inst_offset
));
4845 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4846 code
= emit_memcpy (code
, ainfo
->vtsize
* sizeof (gpointer
), inst
->inst_basereg
, inst
->inst_offset
, ainfo
->reg
, 0);
4848 g_assert_not_reached ();
4853 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
4854 mips_load_const (code
, mips_a0
, cfg
->domain
);
4855 mips_load_const (code
, mips_t9
, (gpointer
)mono_jit_thread_attach
);
4856 mips_jalr (code
, mips_t9
, mips_ra
);
4861 if (method
->save_lmf
) {
4862 mips_load_const (code
, mips_at
, MIPS_LMF_MAGIC1
);
4863 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, magic
));
4865 if (lmf_pthread_key
!= -1) {
4866 g_assert_not_reached();
4868 emit_tls_access (code
, mips_temp
, lmf_pthread_key
);
4870 if (G_STRUCT_OFFSET (MonoJitTlsData
, lmf
))
4871 mips_addiu (code
, mips_a0
, mips_temp
, G_STRUCT_OFFSET (MonoJitTlsData
, lmf
));
4874 mips_addiu (code
, mips_a0
, mips_sp
, lmf_offset
);
4875 mips_load_const (code
, mips_t9
, (gpointer
)mono_trace_lmf_prolog
);
4876 mips_jalr (code
, mips_t9
, mips_ra
);
4879 /* This can/will clobber the a0-a3 registers */
4880 mips_load_const (code
, mips_t9
, (gpointer
)mono_get_lmf_addr
);
4881 mips_jalr (code
, mips_t9
, mips_ra
);
4885 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4886 mips_sw (code
, mips_v0
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
4887 /* new_lmf->previous_lmf = *lmf_addr */
4888 mips_lw (code
, mips_at
, mips_v0
, 0);
4889 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
4890 /* *(lmf_addr) = sp + lmf_offset */
4891 mips_addiu (code
, mips_at
, mips_sp
, lmf_offset
);
4892 mips_sw (code
, mips_at
, mips_v0
, 0);
4894 /* save method info */
4895 mips_load_const (code
, mips_at
, method
);
4896 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, method
));
4897 MIPS_SW (code
, mips_sp
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, ebp
));
4899 /* save the current IP */
4900 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_IP
, NULL
);
4901 mips_load_const (code
, mips_at
, 0x01010101);
4902 mips_sw (code
, mips_at
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, eip
));
4906 cfg
->code_len
= code
- cfg
->native_code
;
4907 g_assert (cfg
->code_len
< cfg
->code_size
);
4922 mono_arch_instrument_epilog (MonoCompile
*cfg
, void *func
, void *p
, gboolean enable_arguments
)
4925 int save_mode
= SAVE_NONE
;
4927 MonoMethod
*method
= cfg
->method
;
4928 int rtype
= mono_type_get_underlying_type (mono_method_signature (method
)->ret
)->type
;
4929 int save_offset
= MIPS_STACK_PARAM_OFFSET
;
4931 g_assert ((save_offset
& (MIPS_STACK_ALIGNMENT
-1)) == 0);
4933 offset
= code
- cfg
->native_code
;
4934 /* we need about 16 instructions */
4935 if (offset
> (cfg
->code_size
- 16 * 4)) {
4936 cfg
->code_size
*= 2;
4937 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
4938 code
= cfg
->native_code
+ offset
;
4943 case MONO_TYPE_VOID
:
4944 /* special case string .ctor icall */
4945 if (strcmp (".ctor", method
->name
) && method
->klass
== mono_defaults
.string_class
)
4946 save_mode
= SAVE_ONE
;
4948 save_mode
= SAVE_NONE
;
4952 save_mode
= SAVE_FP
;
4954 case MONO_TYPE_VALUETYPE
:
4955 save_mode
= SAVE_STRUCT
;
4959 #if SIZEOF_REGISTER == 4
4960 save_mode
= SAVE_TWO
;
4961 #elif SIZEOF_REGISTER == 8
4962 save_mode
= SAVE_ONE
;
4966 save_mode
= SAVE_ONE
;
4970 mips_addiu (code
, mips_sp
, mips_sp
, -32);
4971 switch (save_mode
) {
4973 mips_sw (code
, mips_v0
, mips_sp
, save_offset
);
4974 mips_sw (code
, mips_v1
, mips_sp
, save_offset
+ SIZEOF_REGISTER
);
4975 if (enable_arguments
) {
4976 MIPS_MOVE (code
, mips_a1
, mips_v0
);
4977 MIPS_MOVE (code
, mips_a2
, mips_v1
);
4981 MIPS_SW (code
, mips_v0
, mips_sp
, save_offset
);
4982 if (enable_arguments
) {
4983 MIPS_MOVE (code
, mips_a1
, mips_v0
);
4987 mips_sdc1 (code
, mips_f0
, mips_sp
, save_offset
);
4988 mips_ldc1 (code
, mips_f12
, mips_sp
, save_offset
);
4989 mips_lw (code
, mips_a0
, mips_sp
, save_offset
);
4990 mips_lw (code
, mips_a1
, mips_sp
, save_offset
+ SIZEOF_REGISTER
);
4997 mips_load_const (code
, mips_a0
, cfg
->method
);
4998 mips_load_const (code
, mips_t9
, func
);
4999 mips_jalr (code
, mips_t9
, mips_ra
);
5002 switch (save_mode
) {
5004 mips_lw (code
, mips_v0
, mips_sp
, save_offset
);
5005 mips_lw (code
, mips_v1
, mips_sp
, save_offset
+ SIZEOF_REGISTER
);
5008 MIPS_LW (code
, mips_v0
, mips_sp
, save_offset
);
5011 mips_ldc1 (code
, mips_f0
, mips_sp
, save_offset
);
5018 mips_addiu (code
, mips_sp
, mips_sp
, 32);
5025 mono_arch_emit_epilog_sub (MonoCompile
*cfg
, guint8
*code
)
5027 MonoMethod
*method
= cfg
->method
;
5029 int max_epilog_size
= 16 + 20*4;
5030 guint32 iregs_to_restore
;
5032 guint32 fregs_to_restore
;
5036 if (cfg
->method
->save_lmf
)
5037 max_epilog_size
+= 128;
5040 if (mono_jit_trace_calls
!= NULL
)
5041 max_epilog_size
+= 50;
5043 if (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
)
5044 max_epilog_size
+= 50;
5047 pos
= code
- cfg
->native_code
;
5048 while (cfg
->code_len
+ max_epilog_size
> (cfg
->code_size
- 16)) {
5049 cfg
->code_size
*= 2;
5050 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
5051 mono_jit_stats
.code_reallocs
++;
5055 * Keep in sync with OP_JMP
5058 code
= cfg
->native_code
+ pos
;
5060 code
= cfg
->native_code
+ cfg
->code_len
;
5062 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
)) {
5063 code
= mono_arch_instrument_epilog (cfg
, mono_trace_leave_method
, code
, TRUE
);
5065 pos
= cfg
->arch
.iregs_offset
;
5066 if (cfg
->frame_reg
!= mips_sp
) {
5067 MIPS_MOVE (code
, mips_sp
, cfg
->frame_reg
);
5070 iregs_to_restore
= MONO_ARCH_CALLEE_SAVED_REGS
;
5072 iregs_to_restore
= (cfg
->used_int_regs
& MONO_ARCH_CALLEE_SAVED_REGS
);
5074 if (iregs_to_restore
) {
5075 for (i
= MONO_MAX_IREGS
-1; i
>= 0; --i
) {
5076 if (iregs_to_restore
& (1 << i
)) {
5077 MIPS_LW (code
, i
, mips_sp
, pos
);
5078 pos
+= SIZEOF_REGISTER
;
5085 fregs_to_restore
= (cfg
->used_float_regs
& MONO_ARCH_CALLEE_SAVED_FREGS
);
5087 fregs_to_restore
= MONO_ARCH_CALLEE_SAVED_FREGS
;
5088 fregs_to_restore
|= (fregs_to_restore
<< 1);
5090 if (fregs_to_restore
) {
5091 for (i
= MONO_MAX_FREGS
-1; i
>= 0; --i
) {
5092 if (fregs_to_restore
& (1 << i
)) {
5093 g_assert (pos
< cfg
->stack_usage
- MIPS_STACK_ALIGNMENT
);
5094 mips_lwc1 (code
, i
, mips_sp
, pos
);
5101 /* Unlink the LMF if necessary */
5102 if (method
->save_lmf
) {
5103 int lmf_offset
= cfg
->arch
.lmf_offset
;
5105 /* t0 = current_lmf->previous_lmf */
5106 mips_lw (code
, mips_temp
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
5108 mips_lw (code
, mips_t1
, mips_sp
, lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
5109 /* (*lmf_addr) = previous_lmf */
5110 mips_sw (code
, mips_temp
, mips_t1
, 0);
5114 /* Restore the fp */
5115 mips_lw (code
, mips_fp
, mips_sp
, cfg
->stack_usage
+ MIPS_FP_ADDR_OFFSET
);
5117 /* Correct the stack pointer */
5118 if ((cfg
->flags
& MONO_CFG_HAS_CALLS
) || ALWAYS_SAVE_RA
)
5119 mips_lw (code
, mips_ra
, mips_sp
, cfg
->stack_usage
+ MIPS_RET_ADDR_OFFSET
);
5120 mips_addiu (code
, mips_sp
, mips_sp
, cfg
->stack_usage
);
5122 /* Caller will emit either return or tail-call sequence */
5124 cfg
->code_len
= code
- cfg
->native_code
;
5126 g_assert (cfg
->code_len
< cfg
->code_size
);
5131 mono_arch_emit_epilog (MonoCompile
*cfg
)
5135 code
= mono_arch_emit_epilog_sub (cfg
, NULL
);
5137 mips_jr (code
, mips_ra
);
5140 cfg
->code_len
= code
- cfg
->native_code
;
5142 g_assert (cfg
->code_len
< cfg
->code_size
);
5145 /* remove once throw_exception_by_name is eliminated */
5148 exception_id_by_name (const char *name
)
5150 if (strcmp (name
, "IndexOutOfRangeException") == 0)
5151 return MONO_EXC_INDEX_OUT_OF_RANGE
;
5152 if (strcmp (name
, "OverflowException") == 0)
5153 return MONO_EXC_OVERFLOW
;
5154 if (strcmp (name
, "ArithmeticException") == 0)
5155 return MONO_EXC_ARITHMETIC
;
5156 if (strcmp (name
, "DivideByZeroException") == 0)
5157 return MONO_EXC_DIVIDE_BY_ZERO
;
5158 if (strcmp (name
, "InvalidCastException") == 0)
5159 return MONO_EXC_INVALID_CAST
;
5160 if (strcmp (name
, "NullReferenceException") == 0)
5161 return MONO_EXC_NULL_REF
;
5162 if (strcmp (name
, "ArrayTypeMismatchException") == 0)
5163 return MONO_EXC_ARRAY_TYPE_MISMATCH
;
5164 g_error ("Unknown intrinsic exception %s\n", name
);
5170 mono_arch_emit_exceptions (MonoCompile
*cfg
)
5173 MonoJumpInfo
*patch_info
;
5176 const guint8
* exc_throw_pos
[MONO_EXC_INTRINS_NUM
] = {NULL
};
5177 guint8 exc_throw_found
[MONO_EXC_INTRINS_NUM
] = {0};
5178 int max_epilog_size
= 50;
5180 /* count the number of exception infos */
5183 * make sure we have enough space for exceptions
5184 * 24 is the simulated call to throw_exception_by_name
5186 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5188 if (patch_info
->type
== MONO_PATCH_INFO_EXC
) {
5189 i
= exception_id_by_name (patch_info
->data
.target
);
5190 g_assert (i
< MONO_EXC_INTRINS_NUM
);
5191 if (!exc_throw_found
[i
]) {
5192 max_epilog_size
+= 12;
5193 exc_throw_found
[i
] = TRUE
;
5199 while (cfg
->code_len
+ max_epilog_size
> (cfg
->code_size
- 16)) {
5200 cfg
->code_size
*= 2;
5201 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
5202 mono_jit_stats
.code_reallocs
++;
5205 code
= cfg
->native_code
+ cfg
->code_len
;
5207 /* add code to raise exceptions */
5208 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5209 switch (patch_info
->type
) {
5210 case MONO_PATCH_INFO_EXC
: {
5212 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5214 i
= exception_id_by_name (patch_info
->data
.target
);
5215 g_assert (i
>= 0 && i
< MONO_EXC_INTRINS_NUM
);
5216 if (!exc_throw_pos
[i
]) {
5219 exc_throw_pos
[i
] = code
;
5220 //g_print ("exc: writing stub at %p\n", code);
5221 mips_load_const (code
, mips_a0
, patch_info
->data
.target
);
5222 addr
= (guint32
) mono_arch_get_throw_exception_by_name ();
5223 mips_load_const (code
, mips_t9
, addr
);
5224 mips_jr (code
, mips_t9
);
5227 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5229 /* Turn into a Relative patch, pointing at code stub */
5230 patch_info
->type
= MONO_PATCH_INFO_METHOD_REL
;
5231 patch_info
->data
.offset
= exc_throw_pos
[i
] - cfg
->native_code
;
5233 g_assert_not_reached();
5243 cfg
->code_len
= code
- cfg
->native_code
;
5245 g_assert (cfg
->code_len
< cfg
->code_size
);
5250 * Thread local storage support
5253 setup_tls_access (void)
5256 //guint32 *ins, *code;
5258 if (tls_mode
== TLS_MODE_FAILED
)
5261 if (g_getenv ("MONO_NO_TLS")) {
5262 tls_mode
= TLS_MODE_FAILED
;
5266 if (tls_mode
== TLS_MODE_DETECT
) {
5268 tls_mode
= TLS_MODE_FAILED
;
5272 ins
= (guint32
*)pthread_getspecific
;
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 code
= &cmplwi_1023
;
5286 ppc_cmpli (code
, 0, 0, ppc_r3
, 1023);
5288 ppc_li (code
, ppc_r4
, 0x48);
5291 if (*ins
== cmplwi_1023
) {
5292 int found_lwz_284
= 0;
5293 for (ptk
= 0; ptk
< 20; ++ptk
) {
5295 if (!*ins
|| *ins
== blr_ins
)
5297 if ((guint16
)*ins
== 284 && (*ins
>> 26) == 32) {
5302 if (!found_lwz_284
) {
5303 tls_mode
= TLS_MODE_FAILED
;
5306 tls_mode
= TLS_MODE_LTHREADS
;
5307 } else if (*ins
== li_0x48
) {
5309 /* uncond branch to the real method */
5310 if ((*ins
>> 26) == 18) {
5312 val
= (*ins
& ~3) << 6;
5316 ins
= (guint32
*)val
;
5318 ins
= (guint32
*) ((char*)ins
+ val
);
5321 ppc_li (code
, ppc_r0
, 0x7FF2);
5322 if (ins
[1] == val
) {
5323 /* Darwin on G4, implement */
5324 tls_mode
= TLS_MODE_FAILED
;
5328 ppc_mfspr (code
, ppc_r3
, 104);
5329 if (ins
[1] != val
) {
5330 tls_mode
= TLS_MODE_FAILED
;
5333 tls_mode
= TLS_MODE_DARWIN_G5
;
5336 tls_mode
= TLS_MODE_FAILED
;
5340 tls_mode
= TLS_MODE_FAILED
;
5345 if (monodomain_key
== -1) {
5346 ptk
= mono_domain_get_tls_key ();
5348 ptk
= mono_pthread_key_for_tls (ptk
);
5350 monodomain_key
= ptk
;
5354 if (lmf_pthread_key
== -1) {
5355 ptk
= mono_pthread_key_for_tls (mono_jit_tls_id
);
5357 /*g_print ("MonoLMF at: %d\n", ptk);*/
5358 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5359 init_tls_failed = 1;
5362 lmf_pthread_key
= ptk
;
5365 if (monothread_key
== -1) {
5366 ptk
= mono_thread_get_tls_key ();
5368 ptk
= mono_pthread_key_for_tls (ptk
);
5370 monothread_key
= ptk
;
5371 /*g_print ("thread inited: %d\n", ptk);*/
5374 /*g_print ("thread not inited yet %d\n", ptk);*/
5380 mono_arch_setup_jit_tls_data (MonoJitTlsData
*tls
)
5382 setup_tls_access ();
5386 mono_arch_free_jit_tls_data (MonoJitTlsData
*tls
)
5391 mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
, int this_reg
, int this_type
, int vt_reg
)
5393 int this_dreg
= mips_a0
;
5396 this_dreg
= mips_a1
;
5398 /* add the this argument */
5399 if (this_reg
!= -1) {
5401 MONO_INST_NEW (cfg
, this, OP_MOVE
);
5402 this->type
= this_type
;
5403 this->sreg1
= this_reg
;
5404 this->dreg
= mono_alloc_ireg (cfg
);
5405 mono_bblock_add_inst (cfg
->cbb
, this);
5406 mono_call_inst_add_outarg_reg (cfg
, inst
, this->dreg
, this_dreg
, FALSE
);
5411 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
5412 vtarg
->type
= STACK_MP
;
5413 vtarg
->sreg1
= vt_reg
;
5414 vtarg
->dreg
= mono_alloc_ireg (cfg
);
5415 mono_bblock_add_inst (cfg
->cbb
, vtarg
);
5416 mono_call_inst_add_outarg_reg (cfg
, inst
, vtarg
->dreg
, mips_a0
, FALSE
);
5421 mono_arch_get_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
5423 MonoInst
*ins
= NULL
;
5429 mono_arch_emit_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
5435 mono_arch_print_tree (MonoInst
*tree
, int arity
)
5440 MonoInst
* mono_arch_get_domain_intrinsic (MonoCompile
* cfg
)
5444 setup_tls_access ();
5445 if (monodomain_key
== -1)
5448 MONO_INST_NEW (cfg
, ins
, OP_TLS_GET
);
5449 ins
->inst_offset
= monodomain_key
;
5454 mono_arch_get_thread_intrinsic (MonoCompile
* cfg
)
5458 setup_tls_access ();
5459 if (monothread_key
== -1)
5462 MONO_INST_NEW (cfg
, ins
, OP_TLS_GET
);
5463 ins
->inst_offset
= monothread_key
;
5468 mono_arch_context_get_int_reg (MonoContext
*ctx
, int reg
)
5470 /* FIXME: implement */
5471 g_assert_not_reached ();
5474 #ifdef MONO_ARCH_HAVE_IMT
5478 #define JUMP_IMM_SIZE 12
5479 #define JUMP_IMM32_SIZE 16
5480 #define ENABLE_WRONG_METHOD_CHECK 0
5483 * LOCKING: called with the domain lock held
5486 mono_arch_build_imt_thunk (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
,
5487 gpointer fail_tramp
)
5493 guint8
*code
, *start
;
5495 for (i
= 0; i
< count
; ++i
) {
5496 MonoIMTCheckItem
*item
= imt_entries
[i
];
5497 if (item
->is_equals
) {
5498 if (item
->check_target_idx
) {
5499 if (!item
->compare_done
)
5500 item
->chunk_size
+= CMP_SIZE
;
5502 item
->chunk_size
+= BR_SIZE
+ JUMP_IMM32_SIZE
;
5504 item
->chunk_size
+= BR_SIZE
+ JUMP_IMM_SIZE
;
5507 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
+ JUMP_IMM32_SIZE
* 2;
5509 item
->chunk_size
+= JUMP_IMM_SIZE
;
5510 #if ENABLE_WRONG_METHOD_CHECK
5511 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
+ 4;
5516 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
;
5517 imt_entries
[item
->check_target_idx
]->compare_done
= TRUE
;
5519 size
+= item
->chunk_size
;
5522 code
= mono_method_alloc_generic_virtual_thunk (domain
, size
);
5524 /* the initial load of the vtable address */
5526 code
= mono_domain_code_reserve (domain
, size
);
5530 ppc_load (code
, ppc_r11
, (guint32
)(& (vtable
->vtable
[0])));
5531 for (i
= 0; i
< count
; ++i
) {
5532 MonoIMTCheckItem
*item
= imt_entries
[i
];
5533 item
->code_target
= code
;
5534 if (item
->is_equals
) {
5535 if (item
->check_target_idx
) {
5536 if (!item
->compare_done
) {
5537 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5538 ppc_cmpl (code
, 0, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5540 item
->jmp_code
= code
;
5541 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5543 ppc_load (code
, ppc_r0
, item
->value
.target_code
);
5545 ppc_lwz (code
, ppc_r0
, (sizeof (gpointer
) * item
->value
.vtable_slot
), ppc_r11
);
5546 ppc_mtctr (code
, ppc_r0
);
5547 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5550 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5551 ppc_cmpl (code
, 0, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5552 item
->jmp_code
= code
;
5553 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5554 ppc_load (code
, ppc_r0
, item
->value
.target_code
);
5555 ppc_mtctr (code
, ppc_r0
);
5556 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5557 ppc_patch (item
->jmp_code
, code
);
5558 ppc_load (code
, ppc_r0
, fail_tramp
);
5559 ppc_mtctr (code
, ppc_r0
);
5560 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5561 item
->jmp_code
= NULL
;
5563 /* enable the commented code to assert on wrong method */
5564 #if ENABLE_WRONG_METHOD_CHECK
5565 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5566 ppc_cmpl (code
, 0, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5567 item
->jmp_code
= code
;
5568 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5570 ppc_lwz (code
, ppc_r0
, (sizeof (gpointer
) * item
->value
.vtable_slot
), ppc_r11
);
5571 ppc_mtctr (code
, ppc_r0
);
5572 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5573 #if ENABLE_WRONG_METHOD_CHECK
5574 ppc_patch (item
->jmp_code
, code
);
5576 item
->jmp_code
= NULL
;
5581 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5582 ppc_cmpl (code
, 0, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5583 item
->jmp_code
= code
;
5584 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_LT
, 0);
5587 /* patch the branches to get to the target items */
5588 for (i
= 0; i
< count
; ++i
) {
5589 MonoIMTCheckItem
*item
= imt_entries
[i
];
5590 if (item
->jmp_code
) {
5591 if (item
->check_target_idx
) {
5592 ppc_patch (item
->jmp_code
, imt_entries
[item
->check_target_idx
]->code_target
);
5598 mono_stats
.imt_thunks_size
+= code
- start
;
5599 g_assert (code
- start
<= size
);
5600 mono_arch_flush_icache (start
, size
);
5606 mono_arch_find_imt_method (gpointer
*regs
, guint8
*code
)
5608 return (MonoMethod
*) regs
[MONO_ARCH_IMT_REG
];
5612 mono_arch_find_this_argument (gpointer
*regs
, MonoMethod
*method
, MonoGenericSharingContext
*gsctx
)
5614 return mono_arch_get_this_arg_from_call (gsctx
, mono_method_signature (method
), (gssize
*)regs
, NULL
);
5619 mono_arch_find_static_call_vtable (gpointer
*regs
, guint8
*code
)
5622 return (MonoVTable
*) regs
[MONO_ARCH_RGCTX_REG
];