2 * mini-codegen.c: Arch independent code generation functionality
4 * (C) 2003 Ximian, Inc.
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/debug-helpers.h>
15 #include <mono/metadata/threads.h>
16 #include <mono/metadata/profiler-private.h>
17 #include <mono/utils/mono-math.h>
21 #include "mini-arch.h"
23 #ifndef MONO_MAX_XREGS
25 #define MONO_MAX_XREGS 0
26 #define MONO_ARCH_CALLEE_SAVED_XREGS 0
27 #define MONO_ARCH_CALLEE_XREGS 0
31 * Every hardware register belongs to a register type or register bank. bank 0
32 * contains the int registers, bank 1 contains the fp registers.
33 * int registers are used 99% of the time, so they are special cased in a lot of
37 static const int regbank_size
[] = {
43 static const int regbank_load_ops
[] = {
49 static const int regbank_store_ops
[] = {
51 OP_STORER8_MEMBASE_REG
,
55 static const int regbank_move_ops
[] = {
61 #define regmask(reg) (((regmask_t)1) << (reg))
63 static const regmask_t regbank_callee_saved_regs
[] = {
64 MONO_ARCH_CALLEE_SAVED_REGS
,
65 MONO_ARCH_CALLEE_SAVED_FREGS
,
66 MONO_ARCH_CALLEE_SAVED_XREGS
,
69 static const regmask_t regbank_callee_regs
[] = {
70 MONO_ARCH_CALLEE_REGS
,
71 MONO_ARCH_CALLEE_FREGS
,
72 MONO_ARCH_CALLEE_XREGS
,
75 static const int regbank_spill_var_size
[] = {
78 16 /*FIXME make this a constant. Maybe MONO_ARCH_SIMD_VECTOR_SIZE? */
81 #define DEBUG(a) MINI_DEBUG(cfg->verbose_level, 3, a;)
84 g_slist_append_mempool (MonoMemPool
*mp
, GSList
*list
, gpointer data
)
89 new_list
= mono_mempool_alloc (mp
, sizeof (GSList
));
90 new_list
->data
= data
;
91 new_list
->next
= NULL
;
97 last
->next
= new_list
;
105 mono_regstate_assign (MonoRegState
*rs
)
107 if (rs
->next_vreg
> rs
->vassign_size
) {
108 g_free (rs
->vassign
);
109 rs
->vassign_size
= MAX (rs
->next_vreg
, 256);
110 rs
->vassign
= g_malloc (rs
->vassign_size
* sizeof (int));
113 memset (rs
->isymbolic
, 0, MONO_MAX_IREGS
* sizeof (rs
->isymbolic
[0]));
114 memset (rs
->fsymbolic
, 0, MONO_MAX_FREGS
* sizeof (rs
->fsymbolic
[0]));
116 rs
->symbolic
[0] = rs
->isymbolic
;
117 rs
->symbolic
[1] = rs
->fsymbolic
;
119 #ifdef MONO_ARCH_NEED_SIMD_BANK
120 memset (rs
->xsymbolic
, 0, MONO_MAX_XREGS
* sizeof (rs
->xsymbolic
[0]));
121 rs
->symbolic
[2] = rs
->xsymbolic
;
126 mono_regstate_alloc_int (MonoRegState
*rs
, regmask_t allow
)
128 regmask_t mask
= allow
& rs
->ifree_mask
;
130 #if defined(__x86_64__) && defined(__GNUC__)
137 __asm__("bsfq %1,%0\n\t"
138 : "=r" (i
) : "rm" (mask
));
140 rs
->ifree_mask
&= ~ ((regmask_t
)1 << i
);
146 for (i
= 0; i
< MONO_MAX_IREGS
; ++i
) {
147 if (mask
& ((regmask_t
)1 << i
)) {
148 rs
->ifree_mask
&= ~ ((regmask_t
)1 << i
);
157 mono_regstate_free_int (MonoRegState
*rs
, int reg
)
160 rs
->ifree_mask
|= (regmask_t
)1 << reg
;
161 rs
->isymbolic
[reg
] = 0;
166 mono_regstate_alloc_general (MonoRegState
*rs
, regmask_t allow
, int bank
)
169 regmask_t mask
= allow
& rs
->free_mask
[bank
];
170 for (i
= 0; i
< regbank_size
[bank
]; ++i
) {
171 if (mask
& ((regmask_t
)1 << i
)) {
172 rs
->free_mask
[bank
] &= ~ ((regmask_t
)1 << i
);
180 mono_regstate_free_general (MonoRegState
*rs
, int reg
, int bank
)
183 rs
->free_mask
[bank
] |= (regmask_t
)1 << reg
;
184 rs
->symbolic
[bank
][reg
] = 0;
189 mono_regname_full (int reg
, int bank
)
191 if (G_UNLIKELY (bank
)) {
192 #if MONO_ARCH_NEED_SIMD_BANK
194 return mono_arch_xregname (reg
);
196 g_assert (bank
== 1);
197 return mono_arch_fregname (reg
);
199 return mono_arch_regname (reg
);
204 mono_call_inst_add_outarg_reg (MonoCompile
*cfg
, MonoCallInst
*call
, int vreg
, int hreg
, int bank
)
208 regpair
= (((guint32
)hreg
) << 24) + vreg
;
209 if (G_UNLIKELY (bank
)) {
210 g_assert (vreg
>= regbank_size
[bank
]);
211 g_assert (hreg
< regbank_size
[bank
]);
212 call
->used_fregs
|= 1 << hreg
;
213 call
->out_freg_args
= g_slist_append_mempool (cfg
->mempool
, call
->out_freg_args
, (gpointer
)(gssize
)(regpair
));
215 g_assert (vreg
>= MONO_MAX_IREGS
);
216 g_assert (hreg
< MONO_MAX_IREGS
);
217 call
->used_iregs
|= 1 << hreg
;
218 call
->out_ireg_args
= g_slist_append_mempool (cfg
->mempool
, call
->out_ireg_args
, (gpointer
)(gssize
)(regpair
));
223 resize_spill_info (MonoCompile
*cfg
, int bank
)
225 MonoSpillInfo
*orig_info
= cfg
->spill_info
[bank
];
226 int orig_len
= cfg
->spill_info_len
[bank
];
227 int new_len
= orig_len
? orig_len
* 2 : 16;
228 MonoSpillInfo
*new_info
;
231 g_assert (bank
< MONO_NUM_REGBANKS
);
233 new_info
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoSpillInfo
) * new_len
);
235 memcpy (new_info
, orig_info
, sizeof (MonoSpillInfo
) * orig_len
);
236 for (i
= orig_len
; i
< new_len
; ++i
)
237 new_info
[i
].offset
= -1;
239 cfg
->spill_info
[bank
] = new_info
;
240 cfg
->spill_info_len
[bank
] = new_len
;
244 * returns the offset used by spillvar. It allocates a new
245 * spill variable if necessary.
248 mono_spillvar_offset (MonoCompile
*cfg
, int spillvar
, int bank
)
253 if (G_UNLIKELY (spillvar
>= (cfg
->spill_info_len
[bank
]))) {
254 while (spillvar
>= cfg
->spill_info_len
[bank
])
255 resize_spill_info (cfg
, bank
);
259 * Allocate separate spill slots for fp/non-fp variables since most processors prefer it.
261 info
= &cfg
->spill_info
[bank
][spillvar
];
262 if (info
->offset
== -1) {
263 cfg
->stack_offset
+= sizeof (gpointer
) - 1;
264 cfg
->stack_offset
&= ~(sizeof (gpointer
) - 1);
266 g_assert (bank
< MONO_NUM_REGBANKS
);
267 if (G_UNLIKELY (bank
))
268 size
= regbank_spill_var_size
[bank
];
270 size
= sizeof (gpointer
);
272 if (cfg
->flags
& MONO_CFG_HAS_SPILLUP
) {
273 cfg
->stack_offset
+= size
- 1;
274 cfg
->stack_offset
&= ~(size
- 1);
275 info
->offset
= cfg
->stack_offset
;
276 cfg
->stack_offset
+= size
;
278 cfg
->stack_offset
+= size
- 1;
279 cfg
->stack_offset
&= ~(size
- 1);
280 cfg
->stack_offset
+= size
;
281 info
->offset
= - cfg
->stack_offset
;
288 #define is_hard_ireg(r) ((r) >= 0 && (r) < MONO_MAX_IREGS)
289 #define is_hard_freg(r) ((r) >= 0 && (r) < MONO_MAX_FREGS)
290 #define is_global_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_SAVED_REGS & (regmask (r))))
291 #define is_local_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_REGS & (regmask (r))))
292 #define is_global_freg(r) (is_hard_freg ((r)) && (MONO_ARCH_CALLEE_SAVED_FREGS & (regmask (r))))
293 #define is_local_freg(r) (is_hard_freg ((r)) && (MONO_ARCH_CALLEE_FREGS & (regmask (r))))
295 #define is_hard_reg(r,bank) (G_UNLIKELY (bank) ? ((r) >= 0 && (r) < regbank_size [bank]) : ((r) < MONO_MAX_IREGS))
296 #define is_soft_reg(r,bank) (!is_hard_reg((r),(bank)))
297 #define is_global_reg(r,bank) (G_UNLIKELY (bank) ? (is_hard_reg ((r), (bank)) && (regbank_callee_saved_regs [bank] & regmask (r))) : is_global_ireg (r))
298 #define is_local_reg(r,bank) (G_UNLIKELY (bank) ? (is_hard_reg ((r), (bank)) && (regbank_callee_regs [bank] & regmask (r))) : is_local_ireg (r))
299 #define reg_is_freeable(r,bank) (G_UNLIKELY (bank) ? is_local_reg ((r), (bank)) : is_local_ireg ((r)))
301 #ifndef MONO_ARCH_INST_IS_FLOAT
302 #define MONO_ARCH_INST_IS_FLOAT(desc) ((desc) == 'f')
305 #define reg_is_fp(desc) (MONO_ARCH_INST_IS_FLOAT (desc))
306 #define dreg_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_DEST]))
307 #define sreg1_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_SRC1]))
308 #define sreg2_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_SRC2]))
310 #define reg_is_simd(desc) ((desc) == 'x')
312 #ifdef MONO_ARCH_NEED_SIMD_BANK
314 #define reg_bank(desc) (G_UNLIKELY (reg_is_fp (desc)) ? MONO_REG_DOUBLE : G_UNLIKELY (reg_is_simd(desc)) ? MONO_REG_SIMD : MONO_REG_INT)
318 #define reg_bank(desc) reg_is_fp ((desc))
322 #define sreg1_bank(spec) reg_bank ((spec)[MONO_INST_SRC1])
323 #define sreg2_bank(spec) reg_bank ((spec)[MONO_INST_SRC2])
324 #define dreg_bank(spec) reg_bank ((spec)[MONO_INST_DEST])
326 #define sreg1_bank_ins(ins) sreg1_bank (ins_get_spec ((ins)->opcode))
327 #define sreg2_bank_ins(ins) sreg2_bank (ins_get_spec ((ins)->opcode))
328 #define dreg_bank_ins(ins) dreg_bank (ins_get_spec ((ins)->opcode))
330 #define regpair_reg2_mask(desc,hreg1) ((MONO_ARCH_INST_REGPAIR_REG2 (desc,hreg1) != -1) ? (regmask (MONO_ARCH_INST_REGPAIR_REG2 (desc,hreg1))) : MONO_ARCH_CALLEE_REGS)
332 #ifdef MONO_ARCH_IS_GLOBAL_IREG
333 #undef is_global_ireg
334 #define is_global_ireg(reg) MONO_ARCH_IS_GLOBAL_IREG ((reg))
343 regmask_t preferred_mask
; /* the hreg where the register should be allocated, or 0 */
346 #ifndef DISABLE_LOGGING
348 mono_print_ins_index (int i
, MonoInst
*ins
)
350 const char *spec
= ins_get_spec (ins
->opcode
);
353 printf ("\t%-2d %s", i
, mono_inst_name (ins
->opcode
));
355 printf (" %s", mono_inst_name (ins
->opcode
));
356 if (spec
== MONO_ARCH_CPU_SPEC
) {
357 /* This is a lowered opcode */
359 printf (" R%d <-", ins
->dreg
);
360 if (ins
->sreg1
!= -1)
361 printf (" R%d", ins
->sreg1
);
362 if (ins
->sreg2
!= -1)
363 printf (" R%d", ins
->sreg2
);
365 switch (ins
->opcode
) {
376 if (!(ins
->flags
& MONO_INST_BRLABEL
)) {
377 if (!ins
->inst_false_bb
)
378 printf (" [B%d]", ins
->inst_true_bb
->block_num
);
380 printf (" [B%dB%d]", ins
->inst_true_bb
->block_num
, ins
->inst_false_bb
->block_num
);
388 printf (" [%d (", (int)ins
->inst_c0
);
389 for (i
= 0; i
< ins
->inst_phi_args
[0]; i
++) {
392 printf ("R%d", ins
->inst_phi_args
[i
+ 1]);
398 case OP_OUTARG_VTRETADDR
:
399 printf (" R%d", ((MonoInst
*)ins
->inst_p0
)->dreg
);
402 printf (" + 0x%lx", (long)ins
->inst_offset
);
408 //g_error ("Unknown opcode: %s\n", mono_inst_name (ins->opcode));
412 if (spec
[MONO_INST_DEST
]) {
413 int bank
= dreg_bank (spec
);
414 if (is_soft_reg (ins
->dreg
, bank
)) {
415 if (spec
[MONO_INST_DEST
] == 'b') {
416 if (ins
->inst_offset
== 0)
417 printf (" [R%d] <-", ins
->dreg
);
419 printf (" [R%d + 0x%lx] <-", ins
->dreg
, (long)ins
->inst_offset
);
422 printf (" R%d <-", ins
->dreg
);
423 } else if (spec
[MONO_INST_DEST
] == 'b') {
424 if (ins
->inst_offset
== 0)
425 printf (" [%s] <-", mono_arch_regname (ins
->dreg
));
427 printf (" [%s + 0x%lx] <-", mono_arch_regname (ins
->dreg
), (long)ins
->inst_offset
);
429 printf (" %s <-", mono_regname_full (ins
->dreg
, bank
));
431 if (spec
[MONO_INST_SRC1
]) {
432 int bank
= sreg1_bank (spec
);
433 if (is_soft_reg (ins
->sreg1
, bank
)) {
434 if (spec
[MONO_INST_SRC1
] == 'b')
435 printf (" [R%d + 0x%lx]", ins
->sreg1
, (long)ins
->inst_offset
);
437 printf (" R%d", ins
->sreg1
);
438 } else if (spec
[MONO_INST_SRC1
] == 'b')
439 printf (" [%s + 0x%lx]", mono_arch_regname (ins
->sreg1
), (long)ins
->inst_offset
);
441 printf (" %s", mono_regname_full (ins
->sreg1
, bank
));
443 if (spec
[MONO_INST_SRC2
]) {
444 int bank
= sreg2_bank (spec
);
445 if (is_soft_reg (ins
->sreg2
, bank
))
446 printf (" R%d", ins
->sreg2
);
448 printf (" %s", mono_regname_full (ins
->sreg2
, bank
));
451 switch (ins
->opcode
) {
453 printf (" [%d]", (int)ins
->inst_c0
);
455 #if defined(__i386__) || defined(__x86_64__)
456 case OP_X86_PUSH_IMM
:
458 case OP_ICOMPARE_IMM
:
465 printf (" [%d]", (int)ins
->inst_imm
);
469 printf (" [%d]", (int)(gssize
)ins
->inst_p1
);
472 printf (" [%lld]", (long long)ins
->inst_l
);
475 printf (" [%f]", *(double*)ins
->inst_p0
);
478 printf (" [%f]", *(float*)ins
->inst_p0
);
483 case OP_CALL_MEMBASE
:
492 case OP_VCALL_MEMBASE
:
495 case OP_VCALL2_MEMBASE
:
497 case OP_VOIDCALL_MEMBASE
:
498 case OP_VOIDCALLVIRT
: {
499 MonoCallInst
*call
= (MonoCallInst
*)ins
;
502 if (ins
->opcode
== OP_VCALL
|| ins
->opcode
== OP_VCALL_REG
|| ins
->opcode
== OP_VCALL_MEMBASE
) {
504 * These are lowered opcodes, but they are in the .md files since the old
505 * JIT passes them to backends.
508 printf (" R%d <-", ins
->dreg
);
512 char *full_name
= mono_method_full_name (call
->method
, TRUE
);
513 printf (" [%s]", full_name
);
515 } else if (call
->fptr
) {
516 MonoJitICallInfo
*info
= mono_find_jit_icall_by_addr (call
->fptr
);
518 printf (" [%s]", info
->name
);
521 list
= call
->out_ireg_args
;
526 regpair
= (guint32
)(gssize
)(list
->data
);
527 hreg
= regpair
>> 24;
528 reg
= regpair
& 0xffffff;
530 printf (" [%s <- R%d]", mono_arch_regname (hreg
), reg
);
532 list
= g_slist_next (list
);
537 case OP_CALL_HANDLER
:
538 printf (" [B%d]", ins
->inst_target_bb
->block_num
);
570 if (!(ins
->flags
& MONO_INST_BRLABEL
)) {
571 if (!ins
->inst_false_bb
)
572 printf (" [B%d]", ins
->inst_true_bb
->block_num
);
574 printf (" [B%dB%d]", ins
->inst_true_bb
->block_num
, ins
->inst_false_bb
->block_num
);
581 if (spec
[MONO_INST_CLOB
])
582 printf (" clobbers: %c", spec
[MONO_INST_CLOB
]);
587 print_regtrack (RegTrack
*t
, int num
)
593 for (i
= 0; i
< num
; ++i
) {
596 if (i
>= MONO_MAX_IREGS
) {
597 g_snprintf (buf
, sizeof(buf
), "R%d", i
);
600 r
= mono_arch_regname (i
);
601 printf ("liveness: %s [%d - %d]\n", r
, t
[i
].born_in
, t
[i
].killed_in
);
606 mono_print_ins_index (int i
, MonoInst
*ins
)
609 #endif /* DISABLE_LOGGING */
612 mono_print_ins (MonoInst
*ins
)
614 mono_print_ins_index (-1, ins
);
618 insert_before_ins (MonoBasicBlock
*bb
, MonoInst
*ins
, MonoInst
* to_insert
)
621 * If this function is called multiple times, the new instructions are inserted
622 * in the proper order.
624 mono_bblock_insert_before_ins (bb
, ins
, to_insert
);
628 insert_after_ins (MonoBasicBlock
*bb
, MonoInst
*ins
, MonoInst
**last
, MonoInst
* to_insert
)
631 * If this function is called multiple times, the new instructions are inserted in
634 mono_bblock_insert_after_ins (bb
, *last
, to_insert
);
640 * Force the spilling of the variable in the symbolic register 'reg'.
643 get_register_force_spilling (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoInst
**last
, MonoInst
*ins
, int reg
, int bank
)
648 MonoRegState
*rs
= cfg
->rs
;
650 symbolic
= rs
->symbolic
[bank
];
651 sel
= rs
->vassign
[reg
];
653 /*i = rs->isymbolic [sel];
654 g_assert (i == reg);*/
656 spill
= ++cfg
->spill_count
;
657 rs
->vassign
[i
] = -spill
- 1;
658 if (G_UNLIKELY (bank
))
659 mono_regstate_free_general (rs
, sel
, bank
);
661 mono_regstate_free_int (rs
, sel
);
662 /* we need to create a spill var and insert a load to sel after the current instruction */
663 MONO_INST_NEW (cfg
, load
, regbank_load_ops
[bank
]);
665 load
->inst_basereg
= cfg
->frame_reg
;
666 load
->inst_offset
= mono_spillvar_offset (cfg
, spill
, bank
);
667 insert_after_ins (bb
, ins
, last
, load
);
668 DEBUG (printf ("SPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill
, (long)load
->inst_offset
, i
, mono_regname_full (sel
, bank
)));
669 if (G_UNLIKELY (bank
))
670 i
= mono_regstate_alloc_general (rs
, regmask (sel
), bank
);
672 i
= mono_regstate_alloc_int (rs
, regmask (sel
));
678 /* This isn't defined on older glib versions and on some platforms */
679 #ifndef G_GUINT64_FORMAT
680 #define G_GUINT64_FORMAT "ul"
684 get_register_spilling (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoInst
**last
, MonoInst
*ins
, regmask_t regmask
, int reg
, int bank
)
689 MonoRegState
*rs
= cfg
->rs
;
691 symbolic
= rs
->symbolic
[bank
];
693 g_assert (bank
< MONO_NUM_REGBANKS
);
695 DEBUG (printf ("\tstart regmask to assign R%d: 0x%08" G_GUINT64_FORMAT
" (R%d <- R%d R%d)\n", reg
, (guint64
)regmask
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
));
696 /* exclude the registers in the current instruction */
697 if ((sreg1_bank_ins (ins
) == bank
) && (reg
!= ins
->sreg1
) && (reg_is_freeable (ins
->sreg1
, bank
) || (is_soft_reg (ins
->sreg1
, bank
) && rs
->vassign
[ins
->sreg1
] >= 0))) {
698 if (is_soft_reg (ins
->sreg1
, bank
))
699 regmask
&= ~ (regmask (rs
->vassign
[ins
->sreg1
]));
701 regmask
&= ~ (regmask (ins
->sreg1
));
702 DEBUG (printf ("\t\texcluding sreg1 %s\n", mono_regname_full (ins
->sreg1
, bank
)));
704 if ((sreg2_bank_ins (ins
) == bank
) && (reg
!= ins
->sreg2
) && (reg_is_freeable (ins
->sreg2
, bank
) || (is_soft_reg (ins
->sreg2
, bank
) && rs
->vassign
[ins
->sreg2
] >= 0))) {
705 if (is_soft_reg (ins
->sreg2
, bank
))
706 regmask
&= ~ (regmask (rs
->vassign
[ins
->sreg2
]));
708 regmask
&= ~ (regmask (ins
->sreg2
));
709 DEBUG (printf ("\t\texcluding sreg2 %s %d\n", mono_regname_full (ins
->sreg2
, bank
), ins
->sreg2
));
711 if ((dreg_bank_ins (ins
) == bank
) && (reg
!= ins
->dreg
) && reg_is_freeable (ins
->dreg
, bank
)) {
712 regmask
&= ~ (regmask (ins
->dreg
));
713 DEBUG (printf ("\t\texcluding dreg %s\n", mono_regname_full (ins
->dreg
, bank
)));
716 DEBUG (printf ("\t\tavailable regmask: 0x%08" G_GUINT64_FORMAT
"\n", (guint64
)regmask
));
717 g_assert (regmask
); /* need at least a register we can free */
719 /* we should track prev_use and spill the register that's farther */
720 if (G_UNLIKELY (bank
)) {
721 for (i
= 0; i
< regbank_size
[bank
]; ++i
) {
722 if (regmask
& (regmask (i
))) {
724 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_regname_full (sel
, bank
), rs
->symbolic
[bank
] [sel
]));
729 i
= rs
->symbolic
[bank
] [sel
];
730 spill
= ++cfg
->spill_count
;
731 rs
->vassign
[i
] = -spill
- 1;
732 mono_regstate_free_general (rs
, sel
, bank
);
735 for (i
= 0; i
< MONO_MAX_IREGS
; ++i
) {
736 if (regmask
& (regmask (i
))) {
738 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_regname (sel
), rs
->isymbolic
[sel
]));
743 i
= rs
->isymbolic
[sel
];
744 spill
= ++cfg
->spill_count
;
745 rs
->vassign
[i
] = -spill
- 1;
746 mono_regstate_free_int (rs
, sel
);
749 /* we need to create a spill var and insert a load to sel after the current instruction */
750 MONO_INST_NEW (cfg
, load
, regbank_load_ops
[bank
]);
752 load
->inst_basereg
= cfg
->frame_reg
;
753 load
->inst_offset
= mono_spillvar_offset (cfg
, spill
, bank
);
754 insert_after_ins (bb
, ins
, last
, load
);
755 DEBUG (printf ("\tSPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill
, (long)load
->inst_offset
, i
, mono_regname_full (sel
, bank
)));
756 if (G_UNLIKELY (bank
))
757 i
= mono_regstate_alloc_general (rs
, regmask (sel
), bank
);
759 i
= mono_regstate_alloc_int (rs
, regmask (sel
));
766 free_up_reg (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoInst
**last
, MonoInst
*ins
, int hreg
, int bank
)
768 if (G_UNLIKELY (bank
)) {
769 if (!(cfg
->rs
->free_mask
[1] & (regmask (hreg
)))) {
770 DEBUG (printf ("\tforced spill of R%d\n", cfg
->rs
->symbolic
[bank
] [hreg
]));
771 get_register_force_spilling (cfg
, bb
, last
, ins
, cfg
->rs
->symbolic
[bank
] [hreg
], bank
);
772 mono_regstate_free_general (cfg
->rs
, hreg
, bank
);
776 if (!(cfg
->rs
->ifree_mask
& (regmask (hreg
)))) {
777 DEBUG (printf ("\tforced spill of R%d\n", cfg
->rs
->isymbolic
[hreg
]));
778 get_register_force_spilling (cfg
, bb
, last
, ins
, cfg
->rs
->isymbolic
[hreg
], bank
);
779 mono_regstate_free_int (cfg
->rs
, hreg
);
785 create_copy_ins (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoInst
**last
, int dest
, int src
, MonoInst
*ins
, const unsigned char *ip
, int bank
)
789 MONO_INST_NEW (cfg
, copy
, regbank_move_ops
[bank
]);
795 mono_bblock_insert_after_ins (bb
, ins
, copy
);
798 DEBUG (printf ("\tforced copy from %s to %s\n", mono_regname_full (src
, bank
), mono_regname_full (dest
, bank
)));
803 create_spilled_store (MonoCompile
*cfg
, MonoBasicBlock
*bb
, int spill
, int reg
, int prev_reg
, MonoInst
**last
, MonoInst
*ins
, int bank
)
806 MONO_INST_NEW (cfg
, store
, regbank_store_ops
[bank
]);
808 store
->inst_destbasereg
= cfg
->frame_reg
;
809 store
->inst_offset
= mono_spillvar_offset (cfg
, spill
, bank
);
811 mono_bblock_insert_after_ins (bb
, ins
, store
);
814 DEBUG (printf ("\tSPILLED STORE (%d at 0x%08lx(%%ebp)) R%d (from %s)\n", spill
, (long)store
->inst_offset
, prev_reg
, mono_regname_full (reg
, bank
)));
818 /* flags used in reginfo->flags */
820 MONO_FP_NEEDS_LOAD_SPILL
= regmask (0),
821 MONO_FP_NEEDS_SPILL
= regmask (1),
822 MONO_FP_NEEDS_LOAD
= regmask (2)
826 alloc_int_reg (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoInst
**last
, MonoInst
*ins
, regmask_t dest_mask
, int sym_reg
, RegTrack
*info
)
830 if (info
&& info
->preferred_mask
) {
831 val
= mono_regstate_alloc_int (cfg
->rs
, info
->preferred_mask
& dest_mask
);
833 DEBUG (printf ("\tallocated preferred reg R%d to %s\n", sym_reg
, mono_arch_regname (val
)));
838 val
= mono_regstate_alloc_int (cfg
->rs
, dest_mask
);
840 val
= get_register_spilling (cfg
, bb
, last
, ins
, dest_mask
, sym_reg
, 0);
846 alloc_general_reg (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoInst
**last
, MonoInst
*ins
, regmask_t dest_mask
, int sym_reg
, int bank
)
850 val
= mono_regstate_alloc_general (cfg
->rs
, dest_mask
, bank
);
853 val
= get_register_spilling (cfg
, bb
, last
, ins
, dest_mask
, sym_reg
, bank
);
859 alloc_reg (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoInst
**last
, MonoInst
*ins
, regmask_t dest_mask
, int sym_reg
, RegTrack
*info
, int bank
)
861 if (G_UNLIKELY (bank
))
862 return alloc_general_reg (cfg
, bb
, last
, ins
, dest_mask
, sym_reg
, bank
);
864 return alloc_int_reg (cfg
, bb
, last
, ins
, dest_mask
, sym_reg
, info
);
868 assign_reg (MonoCompile
*cfg
, MonoRegState
*rs
, int reg
, int hreg
, int bank
)
870 if (G_UNLIKELY (bank
)) {
871 g_assert (reg
>= regbank_size
[bank
]);
872 g_assert (hreg
< regbank_size
[bank
]);
873 g_assert (! is_global_freg (hreg
));
875 rs
->vassign
[reg
] = hreg
;
876 rs
->symbolic
[bank
] [hreg
] = reg
;
877 rs
->free_mask
[bank
] &= ~ (regmask (hreg
));
880 g_assert (reg
>= MONO_MAX_IREGS
);
881 g_assert (hreg
< MONO_MAX_IREGS
);
883 /* this seems to trigger a gcc compilation bug sometime (hreg is 0) */
884 g_assert (! is_global_ireg (hreg
));
887 rs
->vassign
[reg
] = hreg
;
888 rs
->isymbolic
[hreg
] = reg
;
889 rs
->ifree_mask
&= ~ (regmask (hreg
));
893 static inline regmask_t
894 get_callee_mask (const char spec
)
896 if (G_UNLIKELY (reg_bank (spec
)))
897 return regbank_callee_regs
[reg_bank (spec
)];
898 return MONO_ARCH_CALLEE_REGS
;
901 static gint8 desc_to_fixed_reg
[256];
902 static gboolean desc_to_fixed_reg_inited
= FALSE
;
905 * Local register allocation.
906 * We first scan the list of instructions and we save the liveness info of
907 * each register (when the register is first used, when it's value is set etc.).
908 * We also reverse the list of instructions because assigning registers backwards allows
909 * for more tricks to be used.
912 mono_local_regalloc (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
914 MonoInst
*ins
, *prev
, *last
;
916 MonoRegState
*rs
= cfg
->rs
;
920 unsigned char spec_src1
, spec_src2
, spec_dest
;
922 #if MONO_ARCH_USE_FPSTACK
923 gboolean has_fp
= FALSE
;
931 if (!desc_to_fixed_reg_inited
) {
932 for (i
= 0; i
< 256; ++i
)
933 desc_to_fixed_reg
[i
] = MONO_ARCH_INST_FIXED_REG (i
);
934 desc_to_fixed_reg_inited
= TRUE
;
937 rs
->next_vreg
= bb
->max_vreg
;
938 mono_regstate_assign (rs
);
940 rs
->ifree_mask
= MONO_ARCH_CALLEE_REGS
;
941 for (i
= 0; i
< MONO_NUM_REGBANKS
; ++i
)
942 rs
->free_mask
[i
] = regbank_callee_regs
[i
];
946 if (cfg
->reginfo
&& cfg
->reginfo_len
< max
)
949 reginfo
= cfg
->reginfo
;
951 cfg
->reginfo_len
= MAX (1024, max
* 2);
952 reginfo
= cfg
->reginfo
= mono_mempool_alloc (cfg
->mempool
, sizeof (RegTrack
) * cfg
->reginfo_len
);
955 g_assert (cfg
->reginfo_len
>= rs
->next_vreg
);
957 if (cfg
->verbose_level
> 1) {
958 /* print_regtrack reads the info of all variables */
959 memset (cfg
->reginfo
, 0, cfg
->reginfo_len
* sizeof (RegTrack
));
963 * For large methods, next_vreg can be very large, so g_malloc0 time can
964 * be prohibitive. So we manually init the reginfo entries used by the
967 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
968 spec
= ins_get_spec (ins
->opcode
);
970 if ((ins
->dreg
!= -1) && (ins
->dreg
< max
)) {
971 memset (®info
[ins
->dreg
], 0, sizeof (RegTrack
));
972 #if SIZEOF_REGISTER == 4
973 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_DEST
])) {
975 * In the new IR, the two vregs of the regpair do not alias the
976 * original long vreg. shift the vreg here so the rest of the
977 * allocator doesn't have to care about it.
980 memset (®info
[ins
->dreg
+ 1], 0, sizeof (RegTrack
));
984 if ((ins
->sreg1
!= -1) && (ins
->sreg1
< max
)) {
985 memset (®info
[ins
->sreg1
], 0, sizeof (RegTrack
));
986 #if SIZEOF_REGISTER == 4
987 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_SRC1
])) {
989 memset (®info
[ins
->sreg1
+ 1], 0, sizeof (RegTrack
));
993 if ((ins
->sreg2
!= -1) && (ins
->sreg2
< max
)) {
994 memset (®info
[ins
->sreg2
], 0, sizeof (RegTrack
));
995 #if SIZEOF_REGISTER == 4
996 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_SRC2
])) {
998 memset (®info
[ins
->sreg2
+ 1], 0, sizeof (RegTrack
));
1004 /*if (cfg->opt & MONO_OPT_COPYPROP)
1005 local_copy_prop (cfg, ins);*/
1008 DEBUG (printf ("\nLOCAL REGALLOC: BASIC BLOCK %d:\n", bb
->block_num
));
1009 /* forward pass on the instructions to collect register liveness info */
1010 MONO_BB_FOR_EACH_INS (bb
, ins
) {
1011 spec
= ins_get_spec (ins
->opcode
);
1012 spec_src1
= spec
[MONO_INST_SRC1
];
1013 spec_src2
= spec
[MONO_INST_SRC2
];
1014 spec_dest
= spec
[MONO_INST_DEST
];
1016 if (G_UNLIKELY (spec
== MONO_ARCH_CPU_SPEC
)) {
1017 g_error ("Opcode '%s' missing from machine description file.", mono_inst_name (ins
->opcode
));
1020 DEBUG (mono_print_ins_index (i
, ins
));
1022 #if MONO_ARCH_USE_FPSTACK
1023 if (sreg1_is_fp (spec
) || sreg2_is_fp (spec
) || dreg_is_fp (spec
))
1028 bank
= sreg1_bank (spec
);
1029 g_assert (ins
->sreg1
!= -1);
1030 if (is_soft_reg (ins
->sreg1
, bank
))
1031 /* This means the vreg is not local to this bb */
1032 g_assert (reginfo
[ins
->sreg1
].born_in
> 0);
1033 rs
->vassign
[ins
->sreg1
] = -1;
1034 //reginfo [ins->sreg1].prev_use = reginfo [ins->sreg1].last_use;
1035 //reginfo [ins->sreg1].last_use = i;
1036 if (MONO_ARCH_INST_IS_REGPAIR (spec_src2
)) {
1037 /* The virtual register is allocated sequentially */
1038 rs
->vassign
[ins
->sreg1
+ 1] = -1;
1039 //reginfo [ins->sreg1 + 1].prev_use = reginfo [ins->sreg1 + 1].last_use;
1040 //reginfo [ins->sreg1 + 1].last_use = i;
1041 if (reginfo
[ins
->sreg1
+ 1].born_in
== 0 || reginfo
[ins
->sreg1
+ 1].born_in
> i
)
1042 reginfo
[ins
->sreg1
+ 1].born_in
= i
;
1048 bank
= sreg2_bank (spec
);
1049 g_assert (ins
->sreg2
!= -1);
1050 if (is_soft_reg (ins
->sreg2
, bank
))
1051 /* This means the vreg is not local to this bb */
1052 g_assert (reginfo
[ins
->sreg2
].born_in
> 0);
1053 rs
->vassign
[ins
->sreg2
] = -1;
1054 //reginfo [ins->sreg2].prev_use = reginfo [ins->sreg2].last_use;
1055 //reginfo [ins->sreg2].last_use = i;
1056 if (MONO_ARCH_INST_IS_REGPAIR (spec_src2
)) {
1057 /* The virtual register is allocated sequentially */
1058 rs
->vassign
[ins
->sreg2
+ 1] = -1;
1059 //reginfo [ins->sreg2 + 1].prev_use = reginfo [ins->sreg2 + 1].last_use;
1060 //reginfo [ins->sreg2 + 1].last_use = i;
1061 if (reginfo
[ins
->sreg2
+ 1].born_in
== 0 || reginfo
[ins
->sreg2
+ 1].born_in
> i
)
1062 reginfo
[ins
->sreg2
+ 1].born_in
= i
;
1070 bank
= dreg_bank (spec
);
1071 if (spec_dest
!= 'b') /* it's not just a base register */
1072 reginfo
[ins
->dreg
].killed_in
= i
;
1073 g_assert (ins
->dreg
!= -1);
1074 rs
->vassign
[ins
->dreg
] = -1;
1075 //reginfo [ins->dreg].prev_use = reginfo [ins->dreg].last_use;
1076 //reginfo [ins->dreg].last_use = i;
1077 if (reginfo
[ins
->dreg
].born_in
== 0 || reginfo
[ins
->dreg
].born_in
> i
)
1078 reginfo
[ins
->dreg
].born_in
= i
;
1080 dest_dreg
= desc_to_fixed_reg
[spec_dest
];
1081 if (dest_dreg
!= -1)
1082 reginfo
[ins
->dreg
].preferred_mask
= (regmask (dest_dreg
));
1084 #ifdef MONO_ARCH_INST_FIXED_MASK
1085 reginfo
[ins
->dreg
].preferred_mask
|= MONO_ARCH_INST_FIXED_MASK (spec_dest
);
1088 if (MONO_ARCH_INST_IS_REGPAIR (spec_dest
)) {
1089 /* The virtual register is allocated sequentially */
1090 rs
->vassign
[ins
->dreg
+ 1] = -1;
1091 //reginfo [ins->dreg + 1].prev_use = reginfo [ins->dreg + 1].last_use;
1092 //reginfo [ins->dreg + 1].last_use = i;
1093 if (reginfo
[ins
->dreg
+ 1].born_in
== 0 || reginfo
[ins
->dreg
+ 1].born_in
> i
)
1094 reginfo
[ins
->dreg
+ 1].born_in
= i
;
1095 if (MONO_ARCH_INST_REGPAIR_REG2 (spec_dest
, -1) != -1)
1096 reginfo
[ins
->dreg
+ 1].preferred_mask
= regpair_reg2_mask (spec_dest
, -1);
1102 if (spec
[MONO_INST_CLOB
] == 'c') {
1103 /* A call instruction implicitly uses all registers in call->out_ireg_args */
1105 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1108 list
= call
->out_ireg_args
;
1114 regpair
= (guint32
)(gssize
)(list
->data
);
1115 hreg
= regpair
>> 24;
1116 reg
= regpair
& 0xffffff;
1118 //reginfo [reg].prev_use = reginfo [reg].last_use;
1119 //reginfo [reg].last_use = i;
1121 list
= g_slist_next (list
);
1125 list
= call
->out_freg_args
;
1131 regpair
= (guint32
)(gssize
)(list
->data
);
1132 hreg
= regpair
>> 24;
1133 reg
= regpair
& 0xffffff;
1135 list
= g_slist_next (list
);
1145 DEBUG (print_regtrack (reginfo
, rs
->next_vreg
));
1146 MONO_BB_FOR_EACH_INS_REVERSE_SAFE (bb
, prev
, ins
) {
1147 int prev_dreg
, prev_sreg1
, prev_sreg2
, clob_dreg
;
1148 int dest_dreg
, dest_sreg1
, dest_sreg2
, clob_reg
;
1149 int dreg_high
, sreg1_high
;
1150 regmask_t dreg_mask
, sreg1_mask
, sreg2_mask
, mask
;
1151 regmask_t dreg_fixed_mask
, sreg1_fixed_mask
, sreg2_fixed_mask
;
1152 const unsigned char *ip
;
1154 spec
= ins_get_spec (ins
->opcode
);
1155 spec_src1
= spec
[MONO_INST_SRC1
];
1156 spec_src2
= spec
[MONO_INST_SRC2
];
1157 spec_dest
= spec
[MONO_INST_DEST
];
1168 dreg_mask
= get_callee_mask (spec_dest
);
1169 sreg1_mask
= get_callee_mask (spec_src1
);
1170 sreg2_mask
= get_callee_mask (spec_src2
);
1172 DEBUG (printf ("processing:"));
1173 DEBUG (mono_print_ins_index (i
, ins
));
1182 dest_sreg1
= desc_to_fixed_reg
[spec_src1
];
1183 dest_sreg2
= desc_to_fixed_reg
[spec_src2
];
1184 dest_dreg
= desc_to_fixed_reg
[spec_dest
];
1185 clob_reg
= desc_to_fixed_reg
[(int)spec
[MONO_INST_CLOB
]];
1186 sreg2_mask
&= ~ (MONO_ARCH_INST_SREG2_MASK (spec
));
1188 #ifdef MONO_ARCH_INST_FIXED_MASK
1189 sreg1_fixed_mask
= MONO_ARCH_INST_FIXED_MASK (spec_src1
);
1190 sreg2_fixed_mask
= MONO_ARCH_INST_FIXED_MASK (spec_src2
);
1191 dreg_fixed_mask
= MONO_ARCH_INST_FIXED_MASK (spec_dest
);
1193 sreg1_fixed_mask
= sreg2_fixed_mask
= dreg_fixed_mask
= 0;
1199 if (dest_sreg2
!= -1) {
1200 if (rs
->ifree_mask
& (regmask (dest_sreg2
))) {
1201 if (is_global_ireg (ins
->sreg2
)) {
1202 /* Argument already in hard reg, need to copy */
1203 MonoInst
*copy
= create_copy_ins (cfg
, bb
, tmp
, dest_sreg2
, ins
->sreg2
, NULL
, ip
, 0);
1204 insert_before_ins (bb
, ins
, copy
);
1207 val
= rs
->vassign
[ins
->sreg2
];
1209 DEBUG (printf ("\tshortcut assignment of R%d to %s\n", ins
->sreg2
, mono_arch_regname (dest_sreg2
)));
1210 assign_reg (cfg
, rs
, ins
->sreg2
, dest_sreg2
, 0);
1211 } else if (val
< -1) {
1213 g_assert_not_reached ();
1215 /* Argument already in hard reg, need to copy */
1216 MonoInst
*copy
= create_copy_ins (cfg
, bb
, tmp
, dest_sreg2
, val
, NULL
, ip
, 0);
1217 insert_before_ins (bb
, ins
, copy
);
1221 gboolean need_spill
= TRUE
;
1222 gboolean need_assign
= TRUE
;
1224 dreg_mask
&= ~ (regmask (dest_sreg2
));
1225 sreg1_mask
&= ~ (regmask (dest_sreg2
));
1228 * First check if dreg is assigned to dest_sreg2, since we
1229 * can't spill a dreg.
1231 val
= rs
->vassign
[ins
->dreg
];
1232 if (val
== dest_sreg2
&& ins
->dreg
!= ins
->sreg2
) {
1234 * the destination register is already assigned to
1235 * dest_sreg2: we need to allocate another register for it
1236 * and then copy from this to dest_sreg2.
1239 new_dest
= alloc_int_reg (cfg
, bb
, tmp
, ins
, dreg_mask
, ins
->dreg
, ®info
[ins
->dreg
]);
1240 g_assert (new_dest
>= 0);
1241 DEBUG (printf ("\tchanging dreg R%d to %s from %s\n", ins
->dreg
, mono_arch_regname (new_dest
), mono_arch_regname (dest_sreg2
)));
1243 prev_dreg
= ins
->dreg
;
1244 assign_reg (cfg
, rs
, ins
->dreg
, new_dest
, 0);
1245 clob_dreg
= ins
->dreg
;
1246 create_copy_ins (cfg
, bb
, tmp
, dest_sreg2
, new_dest
, ins
, ip
, 0);
1247 mono_regstate_free_int (rs
, dest_sreg2
);
1251 if (is_global_ireg (ins
->sreg2
)) {
1252 MonoInst
*copy
= create_copy_ins (cfg
, bb
, tmp
, dest_sreg2
, ins
->sreg2
, NULL
, ip
, 0);
1253 insert_before_ins (bb
, ins
, copy
);
1254 need_assign
= FALSE
;
1257 val
= rs
->vassign
[ins
->sreg2
];
1258 if (val
== dest_sreg2
) {
1259 /* sreg2 is already assigned to the correct register */
1261 } else if (val
< -1) {
1262 /* sreg2 is spilled, it can be assigned to dest_sreg2 */
1263 } else if (val
>= 0) {
1264 /* sreg2 already assigned to another register */
1266 * We couldn't emit a copy from val to dest_sreg2, because
1267 * val might be spilled later while processing this
1268 * instruction. So we spill sreg2 so it can be allocated to
1271 DEBUG (printf ("\tforced spill of R%d\n", ins
->sreg2
));
1272 free_up_reg (cfg
, bb
, tmp
, ins
, val
, 0);
1277 DEBUG (printf ("\tforced spill of R%d\n", rs
->isymbolic
[dest_sreg2
]));
1278 free_up_reg (cfg
, bb
, tmp
, ins
, dest_sreg2
, 0);
1282 if (rs
->vassign
[ins
->sreg2
] < -1) {
1286 /* Need to emit a spill store */
1287 spill
= - rs
->vassign
[ins
->sreg2
] - 1;
1288 store
= create_spilled_store (cfg
, bb
, spill
, dest_sreg2
, ins
->sreg2
, tmp
, NULL
, bank
);
1289 insert_before_ins (bb
, ins
, store
);
1291 /* force-set sreg2 */
1292 assign_reg (cfg
, rs
, ins
->sreg2
, dest_sreg2
, 0);
1295 ins
->sreg2
= dest_sreg2
;
1301 bank
= dreg_bank (spec
);
1302 if (spec_dest
&& is_soft_reg (ins
->dreg
, bank
)) {
1303 prev_dreg
= ins
->dreg
;
1306 if (spec_dest
== 'b') {
1308 * The dest reg is read by the instruction, not written, so
1309 * avoid allocating sreg1/sreg2 to the same reg.
1311 if (dest_sreg1
!= -1)
1312 dreg_mask
&= ~ (regmask (dest_sreg1
));
1313 if (dest_sreg2
!= -1)
1314 dreg_mask
&= ~ (regmask (dest_sreg2
));
1316 val
= rs
->vassign
[ins
->dreg
];
1317 if (is_soft_reg (ins
->dreg
, bank
) && (val
>= 0) && (!(regmask (val
) & dreg_mask
))) {
1318 /* DREG is already allocated to a register needed for sreg1 */
1319 get_register_force_spilling (cfg
, bb
, tmp
, ins
, ins
->dreg
, 0);
1320 mono_regstate_free_int (rs
, val
);
1325 * If dreg is a fixed regpair, free up both of the needed hregs to avoid
1326 * various complex situations.
1328 if (MONO_ARCH_INST_IS_REGPAIR (spec_dest
)) {
1329 guint32 dreg2
, dest_dreg2
;
1331 g_assert (is_soft_reg (ins
->dreg
, bank
));
1333 if (dest_dreg
!= -1) {
1334 if (rs
->vassign
[ins
->dreg
] != dest_dreg
)
1335 free_up_reg (cfg
, bb
, tmp
, ins
, dest_dreg
, 0);
1337 dreg2
= ins
->dreg
+ 1;
1338 dest_dreg2
= MONO_ARCH_INST_REGPAIR_REG2 (spec_dest
, dest_dreg
);
1339 if (dest_dreg2
!= -1) {
1340 if (rs
->vassign
[dreg2
] != dest_dreg2
)
1341 free_up_reg (cfg
, bb
, tmp
, ins
, dest_dreg2
, 0);
1346 if (dreg_fixed_mask
) {
1348 if (is_global_ireg (ins
->dreg
)) {
1350 * The argument is already in a hard reg, but that reg is
1351 * not usable by this instruction, so allocate a new one.
1353 val
= mono_regstate_alloc_int (rs
, dreg_fixed_mask
);
1355 val
= get_register_spilling (cfg
, bb
, tmp
, ins
, dreg_fixed_mask
, -1, bank
);
1356 mono_regstate_free_int (rs
, val
);
1362 dreg_mask
&= dreg_fixed_mask
;
1365 if (is_soft_reg (ins
->dreg
, bank
)) {
1366 val
= rs
->vassign
[ins
->dreg
];
1371 /* the register gets spilled after this inst */
1374 val
= alloc_reg (cfg
, bb
, tmp
, ins
, dreg_mask
, ins
->dreg
, ®info
[ins
->dreg
], bank
);
1375 assign_reg (cfg
, rs
, ins
->dreg
, val
, bank
);
1377 create_spilled_store (cfg
, bb
, spill
, val
, prev_dreg
, tmp
, ins
, bank
);
1380 DEBUG (printf ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val
, bank
), ins
->dreg
));
1384 /* Handle regpairs */
1385 if (MONO_ARCH_INST_IS_REGPAIR (spec_dest
)) {
1386 int reg2
= prev_dreg
+ 1;
1389 g_assert (prev_dreg
> -1);
1390 g_assert (!is_global_ireg (rs
->vassign
[prev_dreg
]));
1391 mask
= regpair_reg2_mask (spec_dest
, rs
->vassign
[prev_dreg
]);
1394 mask
&= ~regmask (X86_ECX
);
1396 val
= rs
->vassign
[reg2
];
1400 /* the register gets spilled after this inst */
1403 val
= mono_regstate_alloc_int (rs
, mask
);
1405 val
= get_register_spilling (cfg
, bb
, tmp
, ins
, mask
, reg2
, bank
);
1407 create_spilled_store (cfg
, bb
, spill
, val
, reg2
, tmp
, ins
, bank
);
1410 if (! (mask
& (regmask (val
)))) {
1411 val
= mono_regstate_alloc_int (rs
, mask
);
1413 val
= get_register_spilling (cfg
, bb
, tmp
, ins
, mask
, reg2
, bank
);
1415 /* Reallocate hreg to the correct register */
1416 create_copy_ins (cfg
, bb
, tmp
, rs
->vassign
[reg2
], val
, ins
, ip
, bank
);
1418 mono_regstate_free_int (rs
, rs
->vassign
[reg2
]);
1422 DEBUG (printf ("\tassigned dreg-high %s to dest R%d\n", mono_arch_regname (val
), reg2
));
1423 assign_reg (cfg
, rs
, reg2
, val
, bank
);
1426 ins
->backend
.reg3
= val
;
1428 if (reg_is_freeable (val
, bank
) && reg2
>= 0 && (reginfo
[reg2
].born_in
>= i
)) {
1429 DEBUG (printf ("\tfreeable %s (R%d)\n", mono_arch_regname (val
), reg2
));
1430 mono_regstate_free_int (rs
, val
);
1434 if (prev_dreg
>= 0 && is_soft_reg (prev_dreg
, bank
) && (spec_dest
!= 'b')) {
1436 * In theory, we could free up the hreg even if the vreg is alive,
1437 * but branches inside bblocks force us to assign the same hreg
1438 * to a vreg every time it is encountered.
1440 int dreg
= rs
->vassign
[prev_dreg
];
1441 g_assert (dreg
>= 0);
1442 DEBUG (printf ("\tfreeable %s (R%d) (born in %d)\n", mono_regname_full (dreg
, bank
), prev_dreg
, reginfo
[prev_dreg
].born_in
));
1443 if (G_UNLIKELY (bank
))
1444 mono_regstate_free_general (rs
, dreg
, bank
);
1446 mono_regstate_free_int (rs
, dreg
);
1447 rs
->vassign
[prev_dreg
] = -1;
1450 if ((dest_dreg
!= -1) && (ins
->dreg
!= dest_dreg
)) {
1451 /* this instruction only outputs to dest_dreg, need to copy */
1452 create_copy_ins (cfg
, bb
, tmp
, ins
->dreg
, dest_dreg
, ins
, ip
, bank
);
1453 ins
->dreg
= dest_dreg
;
1455 if (G_UNLIKELY (bank
)) {
1456 if (rs
->symbolic
[bank
] [dest_dreg
] >= regbank_size
[bank
])
1457 free_up_reg (cfg
, bb
, tmp
, ins
, dest_dreg
, bank
);
1460 if (rs
->isymbolic
[dest_dreg
] >= MONO_MAX_IREGS
)
1461 free_up_reg (cfg
, bb
, tmp
, ins
, dest_dreg
, bank
);
1465 if (spec_dest
== 'b') {
1467 * The dest reg is read by the instruction, not written, so
1468 * avoid allocating sreg1/sreg2 to the same reg.
1470 if (!sreg1_bank (spec
))
1471 sreg1_mask
&= ~ (regmask (ins
->dreg
));
1472 if (!sreg2_bank (spec
))
1473 sreg2_mask
&= ~ (regmask (ins
->dreg
));
1479 if ((clob_reg
!= -1) && (!(rs
->ifree_mask
& (regmask (clob_reg
))))) {
1480 DEBUG (printf ("\tforced spill of clobbered reg R%d\n", rs
->isymbolic
[clob_reg
]));
1481 get_register_force_spilling (cfg
, bb
, tmp
, ins
, rs
->isymbolic
[clob_reg
], 0);
1482 mono_regstate_free_int (rs
, clob_reg
);
1485 if (spec
[MONO_INST_CLOB
] == 'c') {
1486 int j
, s
, dreg
, dreg2
, cur_bank
;
1489 clob_mask
= MONO_ARCH_CALLEE_REGS
;
1491 if (rs
->ifree_mask
!= MONO_ARCH_CALLEE_REGS
) {
1493 * Need to avoid spilling the dreg since the dreg is not really
1494 * clobbered by the call.
1496 if ((prev_dreg
!= -1) && !reg_bank (spec_dest
))
1497 dreg
= rs
->vassign
[prev_dreg
];
1501 if (MONO_ARCH_INST_IS_REGPAIR (spec_dest
))
1502 dreg2
= rs
->vassign
[prev_dreg
+ 1];
1506 for (j
= 0; j
< MONO_MAX_IREGS
; ++j
) {
1508 if ((clob_mask
& s
) && !(rs
->ifree_mask
& s
) && (j
!= ins
->sreg1
)) {
1509 if ((j
!= dreg
) && (j
!= dreg2
))
1510 get_register_force_spilling (cfg
, bb
, tmp
, ins
, rs
->isymbolic
[j
], 0);
1511 else if (rs
->isymbolic
[j
])
1512 /* The hreg is assigned to the dreg of this instruction */
1513 rs
->vassign
[rs
->isymbolic
[j
]] = -1;
1514 mono_regstate_free_int (rs
, j
);
1519 for (cur_bank
= 1; cur_bank
< MONO_NUM_REGBANKS
; ++ cur_bank
) {
1520 if (rs
->free_mask
[cur_bank
] != regbank_callee_regs
[cur_bank
]) {
1521 clob_mask
= regbank_callee_regs
[cur_bank
];
1522 if ((prev_dreg
!= -1) && reg_bank (spec_dest
))
1523 dreg
= rs
->vassign
[prev_dreg
];
1527 for (j
= 0; j
< regbank_size
[cur_bank
]; ++j
) {
1529 if ((clob_mask
& s
) && !(rs
->free_mask
[cur_bank
] & s
) && (j
!= ins
->sreg1
)) {
1531 get_register_force_spilling (cfg
, bb
, tmp
, ins
, rs
->symbolic
[cur_bank
] [j
], cur_bank
);
1532 else if (rs
->symbolic
[cur_bank
] [j
])
1533 /* The hreg is assigned to the dreg of this instruction */
1534 rs
->vassign
[rs
->symbolic
[cur_bank
] [j
]] = -1;
1535 mono_regstate_free_general (rs
, j
, cur_bank
);
1543 * TRACK ARGUMENT REGS
1545 if (spec
[MONO_INST_CLOB
] == 'c') {
1546 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1550 * This needs to be done before assigning sreg1, so sreg1 will
1551 * not be assigned one of the argument regs.
1555 * Assign all registers in call->out_reg_args to the proper
1556 * argument registers.
1559 list
= call
->out_ireg_args
;
1565 regpair
= (guint32
)(gssize
)(list
->data
);
1566 hreg
= regpair
>> 24;
1567 reg
= regpair
& 0xffffff;
1569 assign_reg (cfg
, rs
, reg
, hreg
, 0);
1571 sreg1_mask
&= ~(regmask (hreg
));
1573 DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_regname (hreg
), reg
));
1575 list
= g_slist_next (list
);
1579 list
= call
->out_freg_args
;
1585 regpair
= (guint32
)(gssize
)(list
->data
);
1586 hreg
= regpair
>> 24;
1587 reg
= regpair
& 0xffffff;
1589 assign_reg (cfg
, rs
, reg
, hreg
, 1);
1591 DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_regname_full (hreg
, 1), reg
));
1593 list
= g_slist_next (list
);
1601 bank
= sreg1_bank (spec
);
1602 if (MONO_ARCH_INST_IS_REGPAIR (spec_dest
) && (spec
[MONO_INST_CLOB
] == '1')) {
1603 g_assert (is_soft_reg (ins
->sreg1
, bank
));
1605 /* To simplify things, we allocate the same regpair to sreg1 and dreg */
1606 if (dest_sreg1
!= -1)
1607 g_assert (dest_sreg1
== ins
->dreg
);
1608 val
= mono_regstate_alloc_int (rs
, regmask (ins
->dreg
));
1609 g_assert (val
>= 0);
1611 if (rs
->vassign
[ins
->sreg1
] >= 0 && rs
->vassign
[ins
->sreg1
] != val
)
1613 g_assert_not_reached ();
1615 assign_reg (cfg
, rs
, ins
->sreg1
, val
, bank
);
1617 DEBUG (printf ("\tassigned sreg1-low %s to R%d\n", mono_regname_full (val
, bank
), ins
->sreg1
));
1619 g_assert ((regmask (dreg_high
)) & regpair_reg2_mask (spec_src1
, ins
->dreg
));
1620 val
= mono_regstate_alloc_int (rs
, regmask (dreg_high
));
1621 g_assert (val
>= 0);
1623 if (rs
->vassign
[ins
->sreg1
+ 1] >= 0 && rs
->vassign
[ins
->sreg1
+ 1] != val
)
1625 g_assert_not_reached ();
1627 assign_reg (cfg
, rs
, ins
->sreg1
+ 1, val
, bank
);
1629 DEBUG (printf ("\tassigned sreg1-high %s to R%d\n", mono_regname_full (val
, bank
), ins
->sreg1
+ 1));
1631 /* Skip rest of this section */
1635 if (sreg1_fixed_mask
) {
1637 if (is_global_ireg (ins
->sreg1
)) {
1639 * The argument is already in a hard reg, but that reg is
1640 * not usable by this instruction, so allocate a new one.
1642 val
= mono_regstate_alloc_int (rs
, sreg1_fixed_mask
);
1644 val
= get_register_spilling (cfg
, bb
, tmp
, ins
, sreg1_fixed_mask
, -1, bank
);
1645 mono_regstate_free_int (rs
, val
);
1648 /* Fall through to the dest_sreg1 != -1 case */
1651 sreg1_mask
&= sreg1_fixed_mask
;
1654 if (dest_sreg1
!= -1) {
1655 sreg1_mask
= regmask (dest_sreg1
);
1657 if ((rs
->vassign
[ins
->sreg1
] != dest_sreg1
) && !(rs
->ifree_mask
& (regmask (dest_sreg1
)))) {
1658 DEBUG (printf ("\tforced spill of R%d\n", rs
->isymbolic
[dest_sreg1
]));
1659 get_register_force_spilling (cfg
, bb
, tmp
, ins
, rs
->isymbolic
[dest_sreg1
], 0);
1660 mono_regstate_free_int (rs
, dest_sreg1
);
1662 if (is_global_ireg (ins
->sreg1
)) {
1663 /* The argument is already in a hard reg, need to copy */
1664 MonoInst
*copy
= create_copy_ins (cfg
, bb
, tmp
, dest_sreg1
, ins
->sreg1
, NULL
, ip
, 0);
1665 insert_before_ins (bb
, ins
, copy
);
1666 ins
->sreg1
= dest_sreg1
;
1670 if (is_soft_reg (ins
->sreg1
, bank
)) {
1671 val
= rs
->vassign
[ins
->sreg1
];
1672 prev_sreg1
= ins
->sreg1
;
1676 /* the register gets spilled after this inst */
1680 if ((ins
->opcode
== OP_MOVE
) && !spill
&& !bank
&& is_local_ireg (ins
->dreg
) && (rs
->ifree_mask
& (regmask (ins
->dreg
)))) {
1682 * Allocate the same hreg to sreg1 as well so the
1683 * peephole can get rid of the move.
1685 sreg1_mask
= regmask (ins
->dreg
);
1688 if (spec
[MONO_INST_CLOB
] == '1' && !dreg_bank (spec
) && (rs
->ifree_mask
& (regmask (ins
->dreg
))))
1689 /* Allocate the same reg to sreg1 to avoid a copy later */
1690 sreg1_mask
= regmask (ins
->dreg
);
1692 val
= alloc_reg (cfg
, bb
, tmp
, ins
, sreg1_mask
, ins
->sreg1
, ®info
[ins
->sreg1
], bank
);
1693 assign_reg (cfg
, rs
, ins
->sreg1
, val
, bank
);
1694 DEBUG (printf ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val
, bank
), ins
->sreg1
));
1697 MonoInst
*store
= create_spilled_store (cfg
, bb
, spill
, val
, prev_sreg1
, tmp
, NULL
, bank
);
1699 * Need to insert before the instruction since it can
1702 insert_before_ins (bb
, ins
, store
);
1705 else if ((dest_sreg1
!= -1) && (dest_sreg1
!= val
)) {
1706 MonoInst
*copy
= create_copy_ins (cfg
, bb
, tmp
, dest_sreg1
, val
, NULL
, ip
, bank
);
1707 insert_before_ins (bb
, ins
, copy
);
1708 sreg2_mask
&= ~(regmask (dest_sreg1
));
1717 sreg2_mask
&= ~(regmask (ins
->sreg1
));
1719 /* Handle the case when sreg1 is a regpair but dreg is not */
1720 if (MONO_ARCH_INST_IS_REGPAIR (spec_src1
) && (spec
[MONO_INST_CLOB
] != '1')) {
1721 int reg2
= prev_sreg1
+ 1;
1724 g_assert (prev_sreg1
> -1);
1725 g_assert (!is_global_ireg (rs
->vassign
[prev_sreg1
]));
1726 mask
= regpair_reg2_mask (spec_src1
, rs
->vassign
[prev_sreg1
]);
1727 val
= rs
->vassign
[reg2
];
1731 /* the register gets spilled after this inst */
1734 val
= mono_regstate_alloc_int (rs
, mask
);
1736 val
= get_register_spilling (cfg
, bb
, tmp
, ins
, mask
, reg2
, bank
);
1738 g_assert_not_reached ();
1741 if (! (mask
& (regmask (val
)))) {
1742 /* The vreg is already allocated to a wrong hreg */
1744 g_assert_not_reached ();
1746 val
= mono_regstate_alloc_int (rs
, mask
);
1748 val
= get_register_spilling (cfg
, bb
, tmp
, ins
, mask
, reg2
, bank
);
1750 /* Reallocate hreg to the correct register */
1751 create_copy_ins (cfg
, bb
, tmp
, rs
->vassign
[reg2
], val
, ins
, ip
, bank
);
1753 mono_regstate_free_int (rs
, rs
->vassign
[reg2
]);
1759 DEBUG (printf ("\tassigned sreg1 hreg %s to dest R%d\n", mono_arch_regname (val
), reg2
));
1760 assign_reg (cfg
, rs
, reg2
, val
, bank
);
1763 /* Handle dreg==sreg1 */
1764 if (((dreg_is_fp (spec
) && sreg1_is_fp (spec
)) || spec
[MONO_INST_CLOB
] == '1') && ins
->dreg
!= ins
->sreg1
) {
1765 MonoInst
*sreg2_copy
= NULL
;
1767 int bank
= reg_bank (spec_src1
);
1769 if (ins
->dreg
== ins
->sreg2
) {
1771 * copying sreg1 to dreg could clobber sreg2, so allocate a new
1774 int reg2
= alloc_reg (cfg
, bb
, tmp
, ins
, dreg_mask
, ins
->sreg2
, NULL
, bank
);
1776 DEBUG (printf ("\tneed to copy sreg2 %s to reg %s\n", mono_regname_full (ins
->sreg2
, bank
), mono_regname_full (reg2
, bank
)));
1777 sreg2_copy
= create_copy_ins (cfg
, bb
, tmp
, reg2
, ins
->sreg2
, NULL
, ip
, bank
);
1778 prev_sreg2
= ins
->sreg2
= reg2
;
1780 if (G_UNLIKELY (bank
))
1781 mono_regstate_free_general (rs
, reg2
, bank
);
1783 mono_regstate_free_int (rs
, reg2
);
1786 if (MONO_ARCH_INST_IS_REGPAIR (spec_src1
)) {
1787 /* Copying sreg1_high to dreg could also clobber sreg2 */
1788 if (rs
->vassign
[prev_sreg1
+ 1] == ins
->sreg2
)
1790 g_assert_not_reached ();
1793 * sreg1 and dest are already allocated to the same regpair by the
1794 * SREG1 allocation code.
1796 g_assert (ins
->sreg1
== ins
->dreg
);
1797 g_assert (dreg_high
== sreg1_high
);
1800 DEBUG (printf ("\tneed to copy sreg1 %s to dreg %s\n", mono_regname_full (ins
->sreg1
, bank
), mono_regname_full (ins
->dreg
, bank
)));
1801 copy
= create_copy_ins (cfg
, bb
, tmp
, ins
->dreg
, ins
->sreg1
, NULL
, ip
, bank
);
1802 insert_before_ins (bb
, ins
, copy
);
1805 insert_before_ins (bb
, copy
, sreg2_copy
);
1808 * Need to prevent sreg2 to be allocated to sreg1, since that
1809 * would screw up the previous copy.
1811 sreg2_mask
&= ~ (regmask (ins
->sreg1
));
1812 /* we set sreg1 to dest as well */
1813 prev_sreg1
= ins
->sreg1
= ins
->dreg
;
1814 sreg2_mask
&= ~ (regmask (ins
->dreg
));
1820 bank
= sreg2_bank (spec
);
1821 if (MONO_ARCH_INST_IS_REGPAIR (spec_src2
))
1822 g_assert_not_reached ();
1823 if (is_soft_reg (ins
->sreg2
, bank
)) {
1824 val
= rs
->vassign
[ins
->sreg2
];
1829 /* the register gets spilled after this inst */
1832 val
= alloc_reg (cfg
, bb
, tmp
, ins
, sreg2_mask
, ins
->sreg2
, ®info
[ins
->sreg2
], bank
);
1833 assign_reg (cfg
, rs
, ins
->sreg2
, val
, bank
);
1834 DEBUG (printf ("\tassigned sreg2 %s to R%d\n", mono_regname_full (val
, bank
), ins
->sreg2
));
1836 MonoInst
*store
= create_spilled_store (cfg
, bb
, spill
, val
, prev_sreg2
, tmp
, NULL
, bank
);
1838 * Need to insert before the instruction since it can
1841 insert_before_ins (bb
, ins
, store
);
1850 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
1851 DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg1)));
1852 mono_regstate_free_int (rs, ins->sreg1);
1854 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
1855 DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg2)));
1856 mono_regstate_free_int (rs, ins->sreg2);
1859 DEBUG (mono_print_ins_index (i
, ins
));
1862 // FIXME: Set MAX_FREGS to 8
1863 // FIXME: Optimize generated code
1864 #if MONO_ARCH_USE_FPSTACK
1866 * Make a forward pass over the code, simulating the fp stack, making sure the
1867 * arguments required by the fp opcodes are at the top of the stack.
1870 MonoInst
*prev
= NULL
;
1874 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1875 spec
= ins_get_spec (ins
->opcode
);
1877 DEBUG (printf ("processing:"));
1878 DEBUG (mono_print_ins_index (0, ins
));
1880 if (ins
->opcode
== OP_FMOVE
) {
1881 /* Do it by renaming the source to the destination on the stack */
1882 // FIXME: Is this correct ?
1883 for (i
= 0; i
< sp
; ++i
)
1884 if (fpstack
[i
] == ins
->sreg1
)
1885 fpstack
[i
] = ins
->dreg
;
1890 if (sreg1_is_fp (spec
) && sreg2_is_fp (spec
) && (fpstack
[sp
- 2] != ins
->sreg1
)) {
1891 /* Arg1 must be in %st(1) */
1895 while ((i
< sp
) && (fpstack
[i
] != ins
->sreg1
))
1899 if (sp
- 1 - i
> 0) {
1900 /* First move it to %st(0) */
1901 DEBUG (printf ("\tswap %%st(0) and %%st(%d)\n", sp
- 1 - i
));
1903 MONO_INST_NEW (cfg
, fxch
, OP_X86_FXCH
);
1904 fxch
->inst_imm
= sp
- 1 - i
;
1910 tmp
= fpstack
[sp
- 1];
1911 fpstack
[sp
- 1] = fpstack
[i
];
1915 /* Then move it to %st(1) */
1916 DEBUG (printf ("\tswap %%st(0) and %%st(1)\n"));
1918 MONO_INST_NEW (cfg
, fxch
, OP_X86_FXCH
);
1925 tmp
= fpstack
[sp
- 1];
1926 fpstack
[sp
- 1] = fpstack
[sp
- 2];
1927 fpstack
[sp
- 2] = tmp
;
1930 if (sreg2_is_fp (spec
)) {
1933 if (fpstack
[sp
- 1] != ins
->sreg2
) {
1937 while ((i
< sp
) && (fpstack
[i
] != ins
->sreg2
))
1941 DEBUG (printf ("\tswap %%st(0) and %%st(%d)\n", sp
- 1 - i
));
1943 MONO_INST_NEW (cfg
, fxch
, OP_X86_FXCH
);
1944 fxch
->inst_imm
= sp
- 1 - i
;
1950 tmp
= fpstack
[sp
- 1];
1951 fpstack
[sp
- 1] = fpstack
[i
];
1958 if (sreg1_is_fp (spec
)) {
1961 if (fpstack
[sp
- 1] != ins
->sreg1
) {
1965 while ((i
< sp
) && (fpstack
[i
] != ins
->sreg1
))
1969 DEBUG (printf ("\tswap %%st(0) and %%st(%d)\n", sp
- 1 - i
));
1971 MONO_INST_NEW (cfg
, fxch
, OP_X86_FXCH
);
1972 fxch
->inst_imm
= sp
- 1 - i
;
1978 tmp
= fpstack
[sp
- 1];
1979 fpstack
[sp
- 1] = fpstack
[i
];
1986 if (dreg_is_fp (spec
)) {
1988 fpstack
[sp
++] = ins
->dreg
;
1991 if (G_UNLIKELY (cfg
->verbose_level
>= 2)) {
1993 for (i
= 0; i
< sp
; ++i
)
1994 printf ("%s%%fr%d", (i
> 0) ? ", " : "", fpstack
[i
]);
2001 if (sp
&& bb
!= cfg
->bb_exit
&& !(bb
->out_count
== 1 && bb
->out_bb
[0] == cfg
->bb_exit
)) {
2002 /* Remove remaining items from the fp stack */
2004 * These can remain for example as a result of a dead fmove like in
2005 * System.Collections.Generic.EqualityComparer<double>.Equals ().
2008 MONO_INST_NEW (cfg
, ins
, OP_X86_FPOP
);
2009 mono_add_ins_to_end (bb
, ins
);
2018 mono_opcode_to_cond (int opcode
)
2029 case OP_COND_EXC_EQ
:
2030 case OP_COND_EXC_IEQ
:
2038 case OP_COND_EXC_NE_UN
:
2039 case OP_COND_EXC_INE_UN
:
2040 case OP_CMOV_INE_UN
:
2041 case OP_CMOV_LNE_UN
:
2065 case OP_COND_EXC_LT
:
2066 case OP_COND_EXC_ILT
:
2078 case OP_COND_EXC_GT
:
2079 case OP_COND_EXC_IGT
:
2088 case OP_COND_EXC_LE_UN
:
2089 case OP_COND_EXC_ILE_UN
:
2090 case OP_CMOV_ILE_UN
:
2091 case OP_CMOV_LLE_UN
:
2097 case OP_CMOV_IGE_UN
:
2098 case OP_CMOV_LGE_UN
:
2108 case OP_COND_EXC_LT_UN
:
2109 case OP_COND_EXC_ILT_UN
:
2110 case OP_CMOV_ILT_UN
:
2111 case OP_CMOV_LLT_UN
:
2121 case OP_COND_EXC_GT_UN
:
2122 case OP_COND_EXC_IGT_UN
:
2123 case OP_CMOV_IGT_UN
:
2124 case OP_CMOV_LGT_UN
:
2127 printf ("%s\n", mono_inst_name (opcode
));
2128 g_assert_not_reached ();
2134 mono_negate_cond (CompRelation cond
)
2158 g_assert_not_reached ();
2163 mono_opcode_to_type (int opcode
, int cmp_opcode
)
2165 if ((opcode
>= CEE_BEQ
) && (opcode
<= CEE_BLT_UN
))
2167 else if ((opcode
>= OP_CEQ
) && (opcode
<= OP_CLT_UN
))
2169 else if ((opcode
>= OP_IBEQ
) && (opcode
<= OP_IBLT_UN
))
2171 else if ((opcode
>= OP_ICEQ
) && (opcode
<= OP_ICLT_UN
))
2173 else if ((opcode
>= OP_LBEQ
) && (opcode
<= OP_LBLT_UN
))
2175 else if ((opcode
>= OP_LCEQ
) && (opcode
<= OP_LCLT_UN
))
2177 else if ((opcode
>= OP_FBEQ
) && (opcode
<= OP_FBLT_UN
))
2179 else if ((opcode
>= OP_FCEQ
) && (opcode
<= OP_FCLT_UN
))
2181 else if ((opcode
>= OP_COND_EXC_IEQ
) && (opcode
<= OP_COND_EXC_ILT_UN
))
2183 else if ((opcode
>= OP_COND_EXC_EQ
) && (opcode
<= OP_COND_EXC_LT_UN
)) {
2184 switch (cmp_opcode
) {
2186 case OP_ICOMPARE_IMM
:
2187 case OP_LCOMPARE_IMM
:
2193 g_error ("Unknown opcode '%s' in opcode_to_type", mono_inst_name (opcode
));
2199 mono_is_regsize_var (MonoType
*t
)
2203 t
= mono_type_get_underlying_type (t
);
2205 case MONO_TYPE_BOOLEAN
:
2206 case MONO_TYPE_CHAR
:
2216 case MONO_TYPE_FNPTR
:
2217 #if SIZEOF_REGISTER == 8
2222 case MONO_TYPE_OBJECT
:
2223 case MONO_TYPE_STRING
:
2224 case MONO_TYPE_CLASS
:
2225 case MONO_TYPE_SZARRAY
:
2226 case MONO_TYPE_ARRAY
:
2228 case MONO_TYPE_GENERICINST
:
2229 if (!mono_type_generic_inst_is_valuetype (t
))
2232 case MONO_TYPE_VALUETYPE
:
2239 * mono_peephole_ins:
2241 * Perform some architecture independent peephole optimizations.
2244 mono_peephole_ins (MonoBasicBlock
*bb
, MonoInst
*ins
)
2246 MonoInst
*last_ins
= ins
->prev
;
2248 switch (ins
->opcode
) {
2250 /* remove unnecessary multiplication with 1 */
2251 if (ins
->inst_imm
== 1) {
2252 if (ins
->dreg
!= ins
->sreg1
)
2253 ins
->opcode
= OP_MOVE
;
2255 MONO_DELETE_INS (bb
, ins
);
2258 case OP_LOAD_MEMBASE
:
2259 case OP_LOADI4_MEMBASE
:
2261 * Note: if reg1 = reg2 the load op is removed
2263 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
2264 * OP_LOAD_MEMBASE offset(basereg), reg2
2266 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
2267 * OP_MOVE reg1, reg2
2270 (((ins
->opcode
== OP_LOADI4_MEMBASE
) && (last_ins
->opcode
== OP_STOREI4_MEMBASE_REG
)) ||
2271 ((ins
->opcode
== OP_LOAD_MEMBASE
) && (last_ins
->opcode
== OP_STORE_MEMBASE_REG
))) &&
2272 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2273 ins
->inst_offset
== last_ins
->inst_offset
) {
2274 if (ins
->dreg
== last_ins
->sreg1
) {
2275 MONO_DELETE_INS (bb
, ins
);
2278 ins
->opcode
= OP_MOVE
;
2279 ins
->sreg1
= last_ins
->sreg1
;
2283 * Note: reg1 must be different from the basereg in the second load
2284 * Note: if reg1 = reg2 is equal then second load is removed
2286 * OP_LOAD_MEMBASE offset(basereg), reg1
2287 * OP_LOAD_MEMBASE offset(basereg), reg2
2289 * OP_LOAD_MEMBASE offset(basereg), reg1
2290 * OP_MOVE reg1, reg2
2292 } if (last_ins
&& (last_ins
->opcode
== OP_LOADI4_MEMBASE
2293 || last_ins
->opcode
== OP_LOAD_MEMBASE
) &&
2294 ins
->inst_basereg
!= last_ins
->dreg
&&
2295 ins
->inst_basereg
== last_ins
->inst_basereg
&&
2296 ins
->inst_offset
== last_ins
->inst_offset
) {
2298 if (ins
->dreg
== last_ins
->dreg
) {
2299 MONO_DELETE_INS (bb
, ins
);
2301 ins
->opcode
= OP_MOVE
;
2302 ins
->sreg1
= last_ins
->dreg
;
2305 //g_assert_not_reached ();
2309 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2310 * OP_LOAD_MEMBASE offset(basereg), reg
2312 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2313 * OP_ICONST reg, imm
2315 } else if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_IMM
2316 || last_ins
->opcode
== OP_STORE_MEMBASE_IMM
) &&
2317 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2318 ins
->inst_offset
== last_ins
->inst_offset
) {
2319 ins
->opcode
= OP_ICONST
;
2320 ins
->inst_c0
= last_ins
->inst_imm
;
2321 g_assert_not_reached (); // check this rule
2325 case OP_LOADI1_MEMBASE
:
2326 case OP_LOADU1_MEMBASE
:
2328 * Note: if reg1 = reg2 the load op is removed
2330 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
2331 * OP_LOAD_MEMBASE offset(basereg), reg2
2333 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
2334 * OP_MOVE reg1, reg2
2336 if (last_ins
&& (last_ins
->opcode
== OP_STOREI1_MEMBASE_REG
) &&
2337 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2338 ins
->inst_offset
== last_ins
->inst_offset
) {
2339 ins
->opcode
= (ins
->opcode
== OP_LOADI1_MEMBASE
) ? OP_PCONV_TO_I1
: OP_PCONV_TO_U1
;
2340 ins
->sreg1
= last_ins
->sreg1
;
2343 case OP_LOADI2_MEMBASE
:
2344 case OP_LOADU2_MEMBASE
:
2346 * Note: if reg1 = reg2 the load op is removed
2348 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
2349 * OP_LOAD_MEMBASE offset(basereg), reg2
2351 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
2352 * OP_MOVE reg1, reg2
2354 if (last_ins
&& (last_ins
->opcode
== OP_STOREI2_MEMBASE_REG
) &&
2355 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2356 ins
->inst_offset
== last_ins
->inst_offset
) {
2357 #if SIZEOF_REGISTER == 8
2358 ins
->opcode
= (ins
->opcode
== OP_LOADI2_MEMBASE
) ? OP_PCONV_TO_I2
: OP_PCONV_TO_U2
;
2360 /* The definition of OP_PCONV_TO_U2 is wrong */
2361 ins
->opcode
= (ins
->opcode
== OP_LOADI2_MEMBASE
) ? OP_PCONV_TO_I2
: OP_ICONV_TO_U2
;
2363 ins
->sreg1
= last_ins
->sreg1
;
2373 if (ins
->dreg
== ins
->sreg1
) {
2374 MONO_DELETE_INS (bb
, ins
);
2380 * OP_MOVE sreg, dreg
2381 * OP_MOVE dreg, sreg
2383 if (last_ins
&& last_ins
->opcode
== OP_MOVE
&&
2384 ins
->sreg1
== last_ins
->dreg
&&
2385 ins
->dreg
== last_ins
->sreg1
) {
2386 MONO_DELETE_INS (bb
, ins
);
2390 MONO_DELETE_INS (bb
, ins
);