2 * mini-codegen.c: Arch independent code generation functionality
4 * (C) 2003 Ximian, Inc.
11 #include <mono/metadata/appdomain.h>
12 #include <mono/metadata/debug-helpers.h>
13 #include <mono/metadata/threads.h>
14 #include <mono/metadata/profiler-private.h>
15 #include <mono/utils/mono-math.h>
20 #include "mini-arch.h"
22 #define DEBUG(a) MINI_DEBUG(cfg->verbose_level, 2, a;)
24 #if defined(__x86_64__)
25 const char * const amd64_desc
[OP_LAST
];
26 static const char*const * ins_spec
= amd64_desc
;
27 #elif defined(__sparc__) || defined(sparc)
28 const char * const sparc_desc
[OP_LAST
];
29 static const char*const * ins_spec
= sparc_desc
;
30 #elif defined(__i386__)
31 extern const char * const x86_desc
[OP_LAST
];
32 static const char*const * ins_spec
= x86_desc
;
33 #elif defined(__ia64__)
34 const char * const ia64_desc
[OP_LAST
];
35 static const char*const * ins_spec
= ia64_desc
;
36 #elif defined(__arm__)
37 const char * const arm_cpu_desc
[OP_LAST
];
38 static const char*const * ins_spec
= arm_cpu_desc
;
39 #elif defined(__s390x__)
40 const char * const s390x_cpu_desc
[OP_LAST
];
41 static const char*const * ins_spec
= s390x_cpu_desc
;
42 #elif defined(__s390__)
43 const char * const s390_cpu_desc
[OP_LAST
];
44 static const char*const * ins_spec
= s390_cpu_desc
;
45 #elif defined(__alpha__)
46 const char * const alpha_desc
[OP_LAST
];
47 static const char*const * ins_spec
= alpha_desc
;
48 #elif defined(__ppc__) || defined(__powerpc__)
49 extern const char * const ppcg4
[OP_LAST
];
50 static const char*const * ins_spec
= ppcg4
;
52 #error "Not implemented"
55 #define use_fpstack MONO_ARCH_USE_FPSTACK
58 g_slist_append_mempool (MonoMemPool
*mp
, GSList
*list
, gpointer data
)
63 new_list
= mono_mempool_alloc (mp
, sizeof (GSList
));
64 new_list
->data
= data
;
65 new_list
->next
= NULL
;
71 last
->next
= new_list
;
79 * Duplicated here from regalloc.c so they can be inlined
80 * FIXME: Remove the old one after the new JIT is done
84 mono_regstate2_reset (MonoRegState
*rs
) {
85 rs
->next_vireg
= MONO_MAX_IREGS
;
86 rs
->next_vfreg
= MONO_MAX_FREGS
;
89 static inline MonoRegState
*
90 mono_regstate2_new (void)
92 MonoRegState
* rs
= g_new0 (MonoRegState
, 1);
94 mono_regstate2_reset (rs
);
100 mono_regstate2_free (MonoRegState
*rs
) {
101 g_free (rs
->iassign
);
102 if (rs
->iassign
!= rs
->fassign
)
103 g_free (rs
->fassign
);
108 mono_regstate2_assign (MonoRegState
*rs
) {
111 if (rs
->next_vireg
> rs
->iassign_size
) {
112 g_free (rs
->iassign
);
113 rs
->iassign_size
= MAX (rs
->next_vireg
, 256);
114 rs
->iassign
= g_malloc (rs
->iassign_size
* sizeof (int));
117 memset (rs
->isymbolic
, 0, MONO_MAX_IREGS
* sizeof (rs
->isymbolic
[0]));
118 memset (rs
->iassign
, -1, sizeof (rs
->iassign
[0]) * rs
->next_vireg
);
120 if (rs
->next_vfreg
> rs
->fassign_size
) {
121 g_free (rs
->fassign
);
122 rs
->fassign
= g_malloc (MAX (MONO_MAX_FREGS
, rs
->next_vfreg
) * sizeof (int));
123 rs
->fassign_size
= rs
->next_vfreg
;
126 if (rs
->next_vfreg
> MONO_MAX_FREGS
) {
127 memset (rs
->fsymbolic
, 0, MONO_MAX_IREGS
* sizeof (rs
->fsymbolic
[0]));
128 memset (rs
->fassign
, -1, sizeof (rs
->fassign
[0]) * rs
->next_vfreg
);
133 mono_regstate2_alloc_int (MonoRegState
*rs
, regmask_t allow
)
136 regmask_t mask
= allow
& rs
->ifree_mask
;
137 for (i
= 0; i
< MONO_MAX_IREGS
; ++i
) {
138 if (mask
& ((regmask_t
)1 << i
)) {
139 rs
->ifree_mask
&= ~ ((regmask_t
)1 << i
);
140 rs
->max_ireg
= MAX (rs
->max_ireg
, i
);
148 mono_regstate2_free_int (MonoRegState
*rs
, int reg
)
151 rs
->ifree_mask
|= (regmask_t
)1 << reg
;
152 rs
->isymbolic
[reg
] = 0;
157 mono_regstate2_alloc_float (MonoRegState
*rs
, regmask_t allow
)
160 regmask_t mask
= allow
& rs
->ffree_mask
;
161 for (i
= 0; i
< MONO_MAX_FREGS
; ++i
) {
162 if (mask
& ((regmask_t
)1 << i
)) {
163 rs
->ffree_mask
&= ~ ((regmask_t
)1 << i
);
171 mono_regstate2_free_float (MonoRegState
*rs
, int reg
)
174 rs
->ffree_mask
|= (regmask_t
)1 << reg
;
175 rs
->fsymbolic
[reg
] = 0;
180 mono_regstate2_next_long (MonoRegState
*rs
)
182 int rval
= rs
->next_vireg
;
190 mono_regname_full (int reg
, gboolean fp
)
193 return mono_arch_fregname (reg
);
195 return mono_arch_regname (reg
);
199 mono_call_inst_add_outarg_reg (MonoCompile
*cfg
, MonoCallInst
*call
, int vreg
, int hreg
, gboolean fp
)
203 regpair
= (((guint32
)hreg
) << 24) + vreg
;
205 call
->used_fregs
|= 1 << hreg
;
206 call
->out_freg_args
= g_slist_append_mempool (cfg
->mempool
, call
->out_freg_args
, (gpointer
)(gssize
)(regpair
));
208 call
->used_iregs
|= 1 << hreg
;
209 call
->out_ireg_args
= g_slist_append_mempool (cfg
->mempool
, call
->out_ireg_args
, (gpointer
)(gssize
)(regpair
));
214 resize_spill_info (MonoCompile
*cfg
, gboolean fp
)
216 MonoSpillInfo
*orig_info
= fp
? cfg
->spill_info_float
: cfg
->spill_info
;
217 int orig_len
= fp
? cfg
->spill_info_float_len
: cfg
->spill_info_len
;
218 int new_len
= orig_len
? orig_len
* 2 : 16;
219 MonoSpillInfo
*new_info
;
222 new_info
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoSpillInfo
) * new_len
);
224 memcpy (new_info
, orig_info
, sizeof (MonoSpillInfo
) * orig_len
);
225 for (i
= orig_len
; i
< new_len
; ++i
)
226 new_info
[i
].offset
= -1;
229 cfg
->spill_info
= new_info
;
230 cfg
->spill_info_len
= new_len
;
232 cfg
->spill_info_float
= new_info
;
233 cfg
->spill_info_float_len
= new_len
;
238 * returns the offset used by spillvar. It allocates a new
239 * spill variable if necessary.
242 mono_spillvar_offset (MonoCompile
*cfg
, int spillvar
)
246 if (G_UNLIKELY (spillvar
>= cfg
->spill_info_len
)) {
247 resize_spill_info (cfg
, FALSE
);
248 g_assert (spillvar
< cfg
->spill_info_len
);
251 info
= &cfg
->spill_info
[spillvar
];
252 if (info
->offset
== -1) {
253 cfg
->stack_offset
+= sizeof (gpointer
) - 1;
254 cfg
->stack_offset
&= ~(sizeof (gpointer
) - 1);
256 if (cfg
->flags
& MONO_CFG_HAS_SPILLUP
) {
257 info
->offset
= cfg
->stack_offset
;
258 cfg
->stack_offset
+= sizeof (gpointer
);
260 cfg
->stack_offset
+= sizeof (gpointer
);
261 info
->offset
= - cfg
->stack_offset
;
268 #if MONO_ARCH_USE_FPSTACK
271 * returns the offset used by spillvar. It allocates a new
272 * spill float variable if necessary.
273 * (same as mono_spillvar_offset but for float)
276 mono_spillvar_offset_float (MonoCompile
*cfg
, int spillvar
)
280 if (G_UNLIKELY (spillvar
>= cfg
->spill_info_float_len
)) {
281 resize_spill_info (cfg
, TRUE
);
282 g_assert (spillvar
< cfg
->spill_info_float_len
);
285 info
= &cfg
->spill_info_float
[spillvar
];
286 if (info
->offset
== -1) {
287 cfg
->stack_offset
+= sizeof (double) - 1;
288 cfg
->stack_offset
&= ~(sizeof (double) - 1);
290 if (cfg
->flags
& MONO_CFG_HAS_SPILLUP
) {
291 info
->offset
= cfg
->stack_offset
;
292 cfg
->stack_offset
+= sizeof (double);
294 cfg
->stack_offset
+= sizeof (double);
295 info
->offset
= - cfg
->stack_offset
;
303 * Creates a store for spilled floating point items
306 create_spilled_store_float (MonoCompile
*cfg
, int spill
, int reg
, MonoInst
*ins
)
309 MONO_INST_NEW (cfg
, store
, OP_STORER8_MEMBASE_REG
);
311 store
->inst_destbasereg
= cfg
->frame_reg
;
312 store
->inst_offset
= mono_spillvar_offset_float (cfg
, spill
);
314 DEBUG (printf ("SPILLED FLOAT STORE (%d at 0x%08lx(%%sp)) (from %d)\n", spill
, (long)store
->inst_offset
, reg
));
319 * Creates a load for spilled floating point items
322 create_spilled_load_float (MonoCompile
*cfg
, int spill
, int reg
, MonoInst
*ins
)
325 MONO_INST_NEW (cfg
, load
, OP_LOADR8_SPILL_MEMBASE
);
327 load
->inst_basereg
= cfg
->frame_reg
;
328 load
->inst_offset
= mono_spillvar_offset_float (cfg
, spill
);
330 DEBUG (printf ("SPILLED FLOAT LOAD (%d at 0x%08lx(%%sp)) (from %d)\n", spill
, (long)load
->inst_offset
, reg
));
334 #endif /* MONO_ARCH_USE_FPSTACK */
336 #define regmask(reg) (((regmask_t)1) << (reg))
338 #define is_hard_ireg(r) ((r) >= 0 && (r) < MONO_MAX_IREGS)
339 #define is_hard_freg(r) ((r) >= 0 && (r) < MONO_MAX_FREGS)
340 #define is_global_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_SAVED_REGS & (regmask (r))))
341 #define is_local_ireg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_REGS & (regmask (r))))
342 #define is_global_freg(r) (is_hard_freg ((r)) && (MONO_ARCH_CALLEE_SAVED_FREGS & (regmask (r))))
343 #define is_local_freg(r) (is_hard_ireg ((r)) && (MONO_ARCH_CALLEE_FREGS & (regmask (r))))
344 #define ireg_is_freeable(r) is_local_ireg ((r))
345 #define freg_is_freeable(r) is_hard_freg ((r))
347 #define reg_is_freeable(r,fp) ((fp) ? freg_is_freeable ((r)) : ireg_is_freeable ((r)))
348 #define is_hard_reg(r,fp) ((fp) ? ((r) < MONO_MAX_FREGS) : ((r) < MONO_MAX_IREGS))
349 #define is_soft_reg(r,fp) (!is_hard_reg((r),(fp)))
350 #define rassign(cfg,reg,fp) ((fp) ? (cfg)->rs->fassign [(reg)] : (cfg)->rs->iassign [(reg)])
352 #ifdef MONO_ARCH_INST_IS_FLOAT
353 #define dreg_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_DEST]))
354 #define sreg1_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_SRC1]))
355 #define sreg2_is_fp(spec) (MONO_ARCH_INST_IS_FLOAT (spec [MONO_INST_SRC2]))
357 #define sreg1_is_fp(spec) (spec [MONO_INST_SRC1] == 'f')
358 #define sreg2_is_fp(spec) (spec [MONO_INST_SRC2] == 'f')
359 #define dreg_is_fp(spec) (spec [MONO_INST_DEST] == 'f')
362 #define sreg1_is_fp_ins(ins) (sreg1_is_fp (ins_spec [(ins)->opcode]))
363 #define sreg2_is_fp_ins(ins) (sreg2_is_fp (ins_spec [(ins)->opcode]))
364 #define dreg_is_fp_ins(ins) (dreg_is_fp (ins_spec [(ins)->opcode]))
366 #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)
368 #ifdef MONO_ARCH_IS_GLOBAL_IREG
369 #undef is_global_ireg
370 #define is_global_ireg(reg) MONO_ARCH_IS_GLOBAL_IREG ((reg))
379 #if MONO_ARCH_USE_FPSTACK
380 int flags
; /* used to track fp spill/load */
382 regmask_t preferred_mask
; /* the hreg where the register should be allocated, or 0 */
385 #ifndef DISABLE_LOGGING
387 print_ins (int i
, MonoInst
*ins
)
389 const char *spec
= ins_spec
[ins
->opcode
];
390 printf ("\t%-2d %s", i
, mono_inst_name (ins
->opcode
));
392 g_error ("Unknown opcode: %s\n", mono_inst_name (ins
->opcode
));
394 if (spec
[MONO_INST_DEST
]) {
395 gboolean fp
= dreg_is_fp_ins (ins
);
396 if (is_soft_reg (ins
->dreg
, fp
)) {
397 if (spec
[MONO_INST_DEST
] == 'b') {
398 if (ins
->inst_offset
== 0)
399 printf (" [R%d] <-", ins
->dreg
);
401 printf (" [R%d + 0x%lx] <-", ins
->dreg
, (long)ins
->inst_offset
);
404 printf (" R%d <-", ins
->dreg
);
405 } else if (spec
[MONO_INST_DEST
] == 'b') {
406 if (ins
->inst_offset
== 0)
407 printf (" [%s] <-", mono_arch_regname (ins
->dreg
));
409 printf (" [%s + 0x%lx] <-", mono_arch_regname (ins
->dreg
), (long)ins
->inst_offset
);
411 printf (" %s <-", mono_regname_full (ins
->dreg
, fp
));
413 if (spec
[MONO_INST_SRC1
]) {
414 gboolean fp
= (spec
[MONO_INST_SRC1
] == 'f');
415 if (is_soft_reg (ins
->sreg1
, fp
))
416 printf (" R%d", ins
->sreg1
);
417 else if (spec
[MONO_INST_SRC1
] == 'b')
418 printf (" [%s + 0x%lx]", mono_arch_regname (ins
->sreg1
), (long)ins
->inst_offset
);
420 printf (" %s", mono_regname_full (ins
->sreg1
, fp
));
422 if (spec
[MONO_INST_SRC2
]) {
423 gboolean fp
= (spec
[MONO_INST_SRC2
] == 'f');
424 if (is_soft_reg (ins
->sreg2
, fp
))
425 printf (" R%d", ins
->sreg2
);
427 printf (" %s", mono_regname_full (ins
->sreg2
, fp
));
429 if (spec
[MONO_INST_CLOB
])
430 printf (" clobbers: %c", spec
[MONO_INST_CLOB
]);
435 print_regtrack (RegTrack
*t
, int num
)
441 for (i
= 0; i
< num
; ++i
) {
444 if (i
>= MONO_MAX_IREGS
) {
445 g_snprintf (buf
, sizeof(buf
), "R%d", i
);
448 r
= mono_arch_regname (i
);
449 printf ("liveness: %s [%d - %d]\n", r
, t
[i
].born_in
, t
[i
].killed_in
);
452 #endif /* DISABLE_LOGGING */
454 typedef struct InstList InstList
;
462 static inline InstList
*
463 inst_list_prepend (guint8
*mem
, InstList
*list
, MonoInst
*data
)
465 InstList
*item
= (InstList
*)mem
;
475 insert_before_ins (MonoInst
*ins
, InstList
*item
, MonoInst
* to_insert
)
480 * If this function is called multiple times, the new instructions are inserted
481 * in the proper order.
485 prev
= item
->next
->data
;
487 while (prev
->next
!= ins
)
489 to_insert
->next
= ins
;
490 prev
->next
= to_insert
;
492 to_insert
->next
= ins
;
496 * insert_after_ins insert the new instruction before item->data, so
497 * we have to modify it to point to the first of the prepended instructions.
499 if (item
->data
== ins
)
500 item
->data
= to_insert
;
504 insert_after_ins (MonoInst
*ins
, InstList
*item
, MonoInst
* to_insert
)
507 while (ins
->next
!= item
->prev
->data
)
510 to_insert
->next
= ins
->next
;
511 ins
->next
= to_insert
;
515 * Force the spilling of the variable in the symbolic register 'reg'.
518 get_register_force_spilling (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, int reg
, gboolean fp
)
522 int *assign
, *symbolic
;
525 assign
= cfg
->rs
->fassign
;
526 symbolic
= cfg
->rs
->fsymbolic
;
529 assign
= cfg
->rs
->iassign
;
530 symbolic
= cfg
->rs
->isymbolic
;
534 /*i = cfg->rs->isymbolic [sel];
535 g_assert (i == reg);*/
537 spill
= ++cfg
->spill_count
;
538 assign
[i
] = -spill
- 1;
540 mono_regstate2_free_float (cfg
->rs
, sel
);
542 mono_regstate2_free_int (cfg
->rs
, sel
);
543 /* we need to create a spill var and insert a load to sel after the current instruction */
545 MONO_INST_NEW (cfg
, load
, OP_LOADR8_MEMBASE
);
547 MONO_INST_NEW (cfg
, load
, OP_LOAD_MEMBASE
);
549 load
->inst_basereg
= cfg
->frame_reg
;
550 load
->inst_offset
= mono_spillvar_offset (cfg
, spill
);
551 insert_after_ins (ins
, item
, load
);
552 DEBUG (printf ("SPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill
, (long)load
->inst_offset
, i
, mono_regname_full (sel
, fp
)));
554 i
= mono_regstate2_alloc_float (cfg
->rs
, regmask (sel
));
556 i
= mono_regstate2_alloc_int (cfg
->rs
, regmask (sel
));
562 /* This isn't defined on older glib versions and on some platforms */
563 #ifndef G_GUINT64_FORMAT
564 #define G_GUINT64_FORMAT "ul"
568 get_register_spilling (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, regmask_t regmask
, int reg
, gboolean fp
)
572 int *assign
, *symbolic
;
575 assign
= cfg
->rs
->fassign
;
576 symbolic
= cfg
->rs
->fsymbolic
;
579 assign
= cfg
->rs
->iassign
;
580 symbolic
= cfg
->rs
->isymbolic
;
583 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
));
584 /* exclude the registers in the current instruction */
585 if ((sreg1_is_fp_ins (ins
) == fp
) && (reg
!= ins
->sreg1
) && (reg_is_freeable (ins
->sreg1
, fp
) || (is_soft_reg (ins
->sreg1
, fp
) && rassign (cfg
, ins
->sreg1
, fp
) >= 0))) {
586 if (is_soft_reg (ins
->sreg1
, fp
))
587 regmask
&= ~ (regmask (rassign (cfg
, ins
->sreg1
, fp
)));
589 regmask
&= ~ (regmask (ins
->sreg1
));
590 DEBUG (printf ("\t\texcluding sreg1 %s\n", mono_regname_full (ins
->sreg1
, fp
)));
592 if ((sreg2_is_fp_ins (ins
) == fp
) && (reg
!= ins
->sreg2
) && (reg_is_freeable (ins
->sreg2
, fp
) || (is_soft_reg (ins
->sreg2
, fp
) && rassign (cfg
, ins
->sreg2
, fp
) >= 0))) {
593 if (is_soft_reg (ins
->sreg2
, fp
))
594 regmask
&= ~ (regmask (rassign (cfg
, ins
->sreg2
, fp
)));
596 regmask
&= ~ (regmask (ins
->sreg2
));
597 DEBUG (printf ("\t\texcluding sreg2 %s %d\n", mono_regname_full (ins
->sreg2
, fp
), ins
->sreg2
));
599 if ((dreg_is_fp_ins (ins
) == fp
) && (reg
!= ins
->dreg
) && reg_is_freeable (ins
->dreg
, fp
)) {
600 regmask
&= ~ (regmask (ins
->dreg
));
601 DEBUG (printf ("\t\texcluding dreg %s\n", mono_regname_full (ins
->dreg
, fp
)));
604 DEBUG (printf ("\t\tavailable regmask: 0x%08" G_GUINT64_FORMAT
"\n", (guint64
)regmask
));
605 g_assert (regmask
); /* need at least a register we can free */
607 /* we should track prev_use and spill the register that's farther */
609 for (i
= 0; i
< MONO_MAX_FREGS
; ++i
) {
610 if (regmask
& (regmask (i
))) {
612 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_fregname (sel
), cfg
->rs
->fsymbolic
[sel
]));
617 i
= cfg
->rs
->fsymbolic
[sel
];
618 spill
= ++cfg
->spill_count
;
619 cfg
->rs
->fassign
[i
] = -spill
- 1;
620 mono_regstate2_free_float (cfg
->rs
, sel
);
623 for (i
= 0; i
< MONO_MAX_IREGS
; ++i
) {
624 if (regmask
& (regmask (i
))) {
626 DEBUG (printf ("\t\tselected register %s has assignment %d\n", mono_arch_regname (sel
), cfg
->rs
->isymbolic
[sel
]));
631 i
= cfg
->rs
->isymbolic
[sel
];
632 spill
= ++cfg
->spill_count
;
633 cfg
->rs
->iassign
[i
] = -spill
- 1;
634 mono_regstate2_free_int (cfg
->rs
, sel
);
637 /* we need to create a spill var and insert a load to sel after the current instruction */
638 MONO_INST_NEW (cfg
, load
, fp
? OP_LOADR8_MEMBASE
: OP_LOAD_MEMBASE
);
640 load
->inst_basereg
= cfg
->frame_reg
;
641 load
->inst_offset
= mono_spillvar_offset (cfg
, spill
);
642 insert_after_ins (ins
, item
, load
);
643 DEBUG (printf ("\tSPILLED LOAD (%d at 0x%08lx(%%ebp)) R%d (freed %s)\n", spill
, (long)load
->inst_offset
, i
, mono_regname_full (sel
, fp
)));
645 i
= mono_regstate2_alloc_float (cfg
->rs
, regmask (sel
));
647 i
= mono_regstate2_alloc_int (cfg
->rs
, regmask (sel
));
654 free_up_ireg (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, int hreg
)
656 if (!(cfg
->rs
->ifree_mask
& (regmask (hreg
)))) {
657 DEBUG (printf ("\tforced spill of R%d\n", cfg
->rs
->isymbolic
[hreg
]));
658 get_register_force_spilling (cfg
, item
, ins
, cfg
->rs
->isymbolic
[hreg
], FALSE
);
659 mono_regstate2_free_int (cfg
->rs
, hreg
);
664 free_up_reg (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, int hreg
, gboolean fp
)
667 if (!(cfg
->rs
->ffree_mask
& (regmask (hreg
)))) {
668 DEBUG (printf ("\tforced spill of R%d\n", cfg
->rs
->isymbolic
[hreg
]));
669 get_register_force_spilling (cfg
, item
, ins
, cfg
->rs
->isymbolic
[hreg
], fp
);
670 mono_regstate2_free_float (cfg
->rs
, hreg
);
674 if (!(cfg
->rs
->ifree_mask
& (regmask (hreg
)))) {
675 DEBUG (printf ("\tforced spill of R%d\n", cfg
->rs
->isymbolic
[hreg
]));
676 get_register_force_spilling (cfg
, item
, ins
, cfg
->rs
->isymbolic
[hreg
], fp
);
677 mono_regstate2_free_int (cfg
->rs
, hreg
);
683 create_copy_ins (MonoCompile
*cfg
, int dest
, int src
, MonoInst
*ins
, const unsigned char *ip
, gboolean fp
)
688 MONO_INST_NEW (cfg
, copy
, OP_FMOVE
);
690 MONO_INST_NEW (cfg
, copy
, OP_MOVE
);
696 copy
->next
= ins
->next
;
697 copy
->cil_code
= ins
->cil_code
;
700 DEBUG (printf ("\tforced copy from %s to %s\n", mono_regname_full (src
, fp
), mono_regname_full (dest
, fp
)));
705 create_spilled_store (MonoCompile
*cfg
, int spill
, int reg
, int prev_reg
, MonoInst
*ins
, gboolean fp
)
708 MONO_INST_NEW (cfg
, store
, fp
? OP_STORER8_MEMBASE_REG
: OP_STORE_MEMBASE_REG
);
710 store
->inst_destbasereg
= cfg
->frame_reg
;
711 store
->inst_offset
= mono_spillvar_offset (cfg
, spill
);
713 store
->next
= ins
->next
;
716 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
, fp
)));
720 /* flags used in reginfo->flags */
722 MONO_FP_NEEDS_LOAD_SPILL
= regmask (0),
723 MONO_FP_NEEDS_SPILL
= regmask (1),
724 MONO_FP_NEEDS_LOAD
= regmask (2)
728 alloc_int_reg (MonoCompile
*cfg
, InstList
*tmp
, MonoInst
*ins
, regmask_t dest_mask
, int sym_reg
, RegTrack
*info
)
732 if (info
&& info
->preferred_mask
) {
733 val
= mono_regstate2_alloc_int (cfg
->rs
, info
->preferred_mask
& dest_mask
);
735 DEBUG (printf ("\tallocated preferred reg R%d to %s\n", sym_reg
, mono_arch_regname (val
)));
740 val
= mono_regstate2_alloc_int (cfg
->rs
, dest_mask
);
742 val
= get_register_spilling (cfg
, tmp
, ins
, dest_mask
, sym_reg
, FALSE
);
748 alloc_float_reg (MonoCompile
*cfg
, InstList
*tmp
, MonoInst
*ins
, regmask_t dest_mask
, int sym_reg
)
752 val
= mono_regstate2_alloc_float (cfg
->rs
, dest_mask
);
755 val
= get_register_spilling (cfg
, tmp
, ins
, dest_mask
, sym_reg
, TRUE
);
762 alloc_reg (MonoCompile
*cfg
, InstList
*tmp
, MonoInst
*ins
, regmask_t dest_mask
, int sym_reg
, RegTrack
*info
, gboolean fp
)
765 return alloc_float_reg (cfg
, tmp
, ins
, dest_mask
, sym_reg
);
767 return alloc_int_reg (cfg
, tmp
, ins
, dest_mask
, sym_reg
, info
);
771 assign_reg (MonoCompile
*cfg
, MonoRegState
*rs
, int reg
, int hreg
, gboolean fp
)
774 g_assert (reg
>= MONO_MAX_FREGS
);
775 g_assert (hreg
< MONO_MAX_FREGS
);
776 g_assert (! is_global_freg (hreg
));
778 rs
->fassign
[reg
] = hreg
;
779 rs
->fsymbolic
[hreg
] = reg
;
780 rs
->ffree_mask
&= ~ (regmask (hreg
));
783 g_assert (reg
>= MONO_MAX_IREGS
);
784 g_assert (hreg
< MONO_MAX_IREGS
);
785 g_assert (! is_global_ireg (hreg
));
787 rs
->iassign
[reg
] = hreg
;
788 rs
->isymbolic
[hreg
] = reg
;
789 rs
->ifree_mask
&= ~ (regmask (hreg
));
794 assign_ireg (MonoCompile
*cfg
, MonoRegState
*rs
, int reg
, int hreg
)
796 assign_reg (cfg
, rs
, reg
, hreg
, FALSE
);
800 * Local register allocation.
801 * We first scan the list of instructions and we save the liveness info of
802 * each register (when the register is first used, when it's value is set etc.).
803 * We also reverse the list of instructions (in the InstList list) because assigning
804 * registers backwards allows for more tricks to be used.
807 mono_local_regalloc (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
810 MonoRegState
*rs
= cfg
->rs
;
811 int i
, val
, fpcount
, ins_count
;
812 RegTrack
*reginfo
, *reginfof
;
813 RegTrack
*reginfo1
, *reginfo2
, *reginfod
;
814 InstList
*tmp
, *reversed
= NULL
;
816 GList
*fspill_list
= NULL
;
819 guint8
*inst_list
, *mem
;
820 #if MONO_ARCH_USE_FPSTACK
821 gboolean need_fpstack
= (use_fpstack
&& bb
->max_freg
> MONO_MAX_FREGS
);
827 rs
->next_vireg
= bb
->max_ireg
;
828 rs
->next_vfreg
= bb
->max_freg
;
829 mono_regstate2_assign (rs
);
831 rs
->ifree_mask
= MONO_ARCH_CALLEE_REGS
;
832 rs
->ffree_mask
= MONO_ARCH_CALLEE_FREGS
;
835 rs
->ffree_mask
= 0xff & ~(regmask (MONO_ARCH_FPSTACK_SIZE
));
839 /*if (cfg->opt & MONO_OPT_COPYPROP)
840 local_copy_prop (cfg, ins);*/
842 if (cfg
->reginfo
&& cfg
->reginfo_len
< rs
->next_vireg
) {
845 reginfo
= cfg
->reginfo
;
847 cfg
->reginfo_len
= MAX (256, rs
->next_vireg
* 2);
848 reginfo
= cfg
->reginfo
= mono_mempool_alloc (cfg
->mempool
, sizeof (RegTrack
) * cfg
->reginfo_len
);
851 g_assert (cfg
->reginfo_len
>= rs
->next_vireg
);
853 if (cfg
->reginfof
&& cfg
->reginfof_len
< rs
->next_vfreg
) {
854 cfg
->reginfof
= NULL
;
856 reginfof
= cfg
->reginfof
;
858 cfg
->reginfof_len
= MAX (256, rs
->next_vfreg
* 2);
859 reginfof
= cfg
->reginfof
= mono_mempool_alloc (cfg
->mempool
, sizeof (RegTrack
) * cfg
->reginfof_len
);
862 g_assert (cfg
->reginfof_len
>= rs
->next_vfreg
);
864 memset (reginfo
, 0, rs
->next_vireg
* sizeof (RegTrack
));
865 memset (reginfof
, 0, rs
->next_vfreg
* sizeof (RegTrack
));
868 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
869 spec
= ins_spec
[ins
->opcode
];
874 if (cfg
->reverse_inst_list
&& (cfg
->reverse_inst_list_len
< ins_count
)) {
875 cfg
->reverse_inst_list
= NULL
;
878 inst_list
= cfg
->reverse_inst_list
;
880 cfg
->reverse_inst_list_len
= MAX (ins_count
, 1024);
881 inst_list
= cfg
->reverse_inst_list
= mono_mempool_alloc (cfg
->mempool
, cfg
->reverse_inst_list_len
* sizeof (InstList
));
887 DEBUG (printf ("\nLOCAL REGALLOC: BASIC BLOCK: %d\n", bb
->block_num
));
888 /* forward pass on the instructions to collect register liveness info */
889 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
890 spec
= ins_spec
[ins
->opcode
];
892 if (G_UNLIKELY (!spec
)) {
893 g_error ("Opcode '%s' missing from machine description file.", mono_inst_name (ins
->opcode
));
896 DEBUG (print_ins (i
, ins
));
901 #if MONO_ARCH_USE_FPSTACK
905 if (spec
[MONO_INST_SRC1
] == 'f') {
906 spill
= g_list_first (fspill_list
);
907 if (spill
&& fpcount
< MONO_ARCH_FPSTACK_SIZE
) {
908 reginfof
[ins
->sreg1
].flags
|= MONO_FP_NEEDS_LOAD
;
909 fspill_list
= g_list_remove (fspill_list
, spill
->data
);
914 if (spec
[MONO_INST_SRC2
] == 'f') {
915 spill
= g_list_first (fspill_list
);
917 reginfof
[ins
->sreg2
].flags
|= MONO_FP_NEEDS_LOAD
;
918 fspill_list
= g_list_remove (fspill_list
, spill
->data
);
919 if (fpcount
>= MONO_ARCH_FPSTACK_SIZE
) {
921 fspill_list
= g_list_prepend (fspill_list
, GINT_TO_POINTER(fspill
));
922 reginfof
[ins
->sreg2
].flags
|= MONO_FP_NEEDS_LOAD_SPILL
;
928 if (dreg_is_fp (spec
)) {
929 if (use_fpstack
&& (spec
[MONO_INST_CLOB
] != 'm')) {
930 if (fpcount
>= MONO_ARCH_FPSTACK_SIZE
) {
931 reginfof
[ins
->dreg
].flags
|= MONO_FP_NEEDS_SPILL
;
933 fspill_list
= g_list_prepend (fspill_list
, GINT_TO_POINTER(fspill
));
942 if (spec
[MONO_INST_SRC1
]) {
943 if (spec
[MONO_INST_SRC1
] == 'f')
947 //reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
948 //reginfo1 [ins->sreg1].last_use = i;
949 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_SRC2
])) {
950 /* The virtual register is allocated sequentially */
951 //reginfo1 [ins->sreg1 + 1].prev_use = reginfo1 [ins->sreg1 + 1].last_use;
952 //reginfo1 [ins->sreg1 + 1].last_use = i;
953 if (reginfo1
[ins
->sreg1
+ 1].born_in
== 0 || reginfo1
[ins
->sreg1
+ 1].born_in
> i
)
954 reginfo1
[ins
->sreg1
+ 1].born_in
= i
;
959 if (spec
[MONO_INST_SRC2
]) {
960 if (spec
[MONO_INST_SRC2
] == 'f')
964 //reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
965 //reginfo2 [ins->sreg2].last_use = i;
966 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_SRC2
])) {
967 /* The virtual register is allocated sequentially */
968 //reginfo2 [ins->sreg2 + 1].prev_use = reginfo2 [ins->sreg2 + 1].last_use;
969 //reginfo2 [ins->sreg2 + 1].last_use = i;
970 if (reginfo2
[ins
->sreg2
+ 1].born_in
== 0 || reginfo2
[ins
->sreg2
+ 1].born_in
> i
)
971 reginfo2
[ins
->sreg2
+ 1].born_in
= i
;
976 if (spec
[MONO_INST_DEST
]) {
979 if (dreg_is_fp (spec
))
983 if (spec
[MONO_INST_DEST
] != 'b') /* it's not just a base register */
984 reginfod
[ins
->dreg
].killed_in
= i
;
985 //reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
986 //reginfod [ins->dreg].last_use = i;
987 if (reginfod
[ins
->dreg
].born_in
== 0 || reginfod
[ins
->dreg
].born_in
> i
)
988 reginfod
[ins
->dreg
].born_in
= i
;
990 dest_dreg
= MONO_ARCH_INST_FIXED_REG (spec
[MONO_INST_DEST
]);
992 reginfod
[ins
->dreg
].preferred_mask
= (regmask (dest_dreg
));
994 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_DEST
])) {
995 /* The virtual register is allocated sequentially */
996 //reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
997 //reginfod [ins->dreg + 1].last_use = i;
998 if (reginfod
[ins
->dreg
+ 1].born_in
== 0 || reginfod
[ins
->dreg
+ 1].born_in
> i
)
999 reginfod
[ins
->dreg
+ 1].born_in
= i
;
1000 if (MONO_ARCH_INST_REGPAIR_REG2 (spec
[MONO_INST_DEST
], -1) != -1)
1001 reginfod
[ins
->dreg
+ 1].preferred_mask
= regpair_reg2_mask (spec
[MONO_INST_DEST
], -1);
1007 if (spec
[MONO_INST_CLOB
] == 'c') {
1008 /* A call instruction implicitly uses all registers in call->out_ireg_args */
1010 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1013 list
= call
->out_ireg_args
;
1019 regpair
= (guint32
)(gssize
)(list
->data
);
1020 hreg
= regpair
>> 24;
1021 reg
= regpair
& 0xffffff;
1023 //reginfo [reg].prev_use = reginfo [reg].last_use;
1024 //reginfo [reg].last_use = i;
1026 list
= g_slist_next (list
);
1030 list
= call
->out_freg_args
;
1031 if (!use_fpstack
&& list
) {
1036 regpair
= (guint32
)(gssize
)(list
->data
);
1037 hreg
= regpair
>> 24;
1038 reg
= regpair
& 0xffffff;
1040 //reginfof [reg].prev_use = reginfof [reg].last_use;
1041 //reginfof [reg].last_use = i;
1043 list
= g_slist_next (list
);
1048 reversed
= inst_list_prepend (mem
, reversed
, ins
);
1049 mem
+= sizeof (InstList
);
1053 // todo: check if we have anything left on fp stack, in verify mode?
1056 DEBUG (print_regtrack (reginfo
, rs
->next_vireg
));
1057 DEBUG (print_regtrack (reginfof
, rs
->next_vfreg
));
1060 int prev_dreg
, prev_sreg1
, prev_sreg2
, clob_dreg
;
1061 int dest_dreg
, dest_sreg1
, dest_sreg2
, clob_reg
;
1062 int dreg_high
, sreg1_high
;
1063 regmask_t dreg_mask
, sreg1_mask
, sreg2_mask
, mask
;
1064 regmask_t dreg_fixed_mask
, sreg1_fixed_mask
, sreg2_fixed_mask
;
1065 const unsigned char *ip
;
1068 spec
= ins_spec
[ins
->opcode
];
1076 dreg_mask
= dreg_is_fp (spec
) ? MONO_ARCH_CALLEE_FREGS
: MONO_ARCH_CALLEE_REGS
;
1077 sreg1_mask
= sreg1_is_fp (spec
) ? MONO_ARCH_CALLEE_FREGS
: MONO_ARCH_CALLEE_REGS
;
1078 sreg2_mask
= sreg2_is_fp (spec
) ? MONO_ARCH_CALLEE_FREGS
: MONO_ARCH_CALLEE_REGS
;
1080 DEBUG (printf ("processing:"));
1081 DEBUG (print_ins (i
, ins
));
1088 dest_sreg1
= MONO_ARCH_INST_FIXED_REG (spec
[MONO_INST_SRC1
]);
1089 dest_sreg2
= MONO_ARCH_INST_FIXED_REG (spec
[MONO_INST_SRC2
]);
1090 dest_dreg
= MONO_ARCH_INST_FIXED_REG (spec
[MONO_INST_DEST
]);
1091 clob_reg
= MONO_ARCH_INST_FIXED_REG (spec
[MONO_INST_CLOB
]);
1092 sreg2_mask
&= ~ (MONO_ARCH_INST_SREG2_MASK (spec
));
1094 #ifdef MONO_ARCH_INST_FIXED_MASK
1095 sreg1_fixed_mask
= MONO_ARCH_INST_FIXED_MASK (spec
[MONO_INST_SRC1
]);
1096 sreg2_fixed_mask
= MONO_ARCH_INST_FIXED_MASK (spec
[MONO_INST_SRC2
]);
1097 dreg_fixed_mask
= MONO_ARCH_INST_FIXED_MASK (spec
[MONO_INST_DEST
]);
1099 sreg1_fixed_mask
= sreg2_fixed_mask
= dreg_fixed_mask
= 0;
1105 #if MONO_ARCH_USE_FPSTACK
1106 if (need_fpstack
&& (spec
[MONO_INST_CLOB
] != 'm')) {
1107 if (dreg_is_fp (spec
)) {
1108 if (reginfof
[ins
->dreg
].flags
& MONO_FP_NEEDS_SPILL
) {
1111 spill_node
= g_list_first (fspill_list
);
1112 g_assert (spill_node
);
1114 store
= create_spilled_store_float (cfg
, GPOINTER_TO_INT (spill_node
->data
), ins
->dreg
, ins
);
1115 insert_before_ins (ins
, tmp
, store
);
1116 fspill_list
= g_list_remove (fspill_list
, spill_node
->data
);
1121 if (spec
[MONO_INST_SRC1
] == 'f') {
1122 if (reginfof
[ins
->sreg1
].flags
& MONO_FP_NEEDS_LOAD
) {
1124 MonoInst
*store
= NULL
;
1126 if (reginfof
[ins
->sreg1
].flags
& MONO_FP_NEEDS_LOAD_SPILL
) {
1128 spill_node
= g_list_first (fspill_list
);
1129 g_assert (spill_node
);
1131 store
= create_spilled_store_float (cfg
, GPOINTER_TO_INT (spill_node
->data
), ins
->sreg1
, ins
);
1132 fspill_list
= g_list_remove (fspill_list
, spill_node
->data
);
1136 fspill_list
= g_list_prepend (fspill_list
, GINT_TO_POINTER(fspill
));
1137 load
= create_spilled_load_float (cfg
, fspill
, ins
->sreg1
, ins
);
1138 insert_before_ins (ins
, tmp
, load
);
1140 insert_before_ins (load
, tmp
, store
);
1144 if (spec
[MONO_INST_SRC2
] == 'f') {
1145 if (reginfof
[ins
->sreg2
].flags
& MONO_FP_NEEDS_LOAD
) {
1147 MonoInst
*store
= NULL
;
1149 if (reginfof
[ins
->sreg2
].flags
& MONO_FP_NEEDS_LOAD_SPILL
) {
1152 spill_node
= g_list_first (fspill_list
);
1153 g_assert (spill_node
);
1154 if (spec
[MONO_INST_SRC1
] == 'f' && (reginfof
[ins
->sreg2
].flags
& MONO_FP_NEEDS_LOAD_SPILL
))
1155 spill_node
= g_list_next (spill_node
);
1157 store
= create_spilled_store_float (cfg
, GPOINTER_TO_INT (spill_node
->data
), ins
->sreg2
, ins
);
1158 fspill_list
= g_list_remove (fspill_list
, spill_node
->data
);
1162 fspill_list
= g_list_prepend (fspill_list
, GINT_TO_POINTER(fspill
));
1163 load
= create_spilled_load_float (cfg
, fspill
, ins
->sreg2
, ins
);
1164 insert_before_ins (ins
, tmp
, load
);
1166 insert_before_ins (load
, tmp
, store
);
1175 if (dest_sreg2
!= -1) {
1176 if (rs
->ifree_mask
& (regmask (dest_sreg2
))) {
1177 if (is_global_ireg (ins
->sreg2
)) {
1178 /* Argument already in hard reg, need to copy */
1179 MonoInst
*copy
= create_copy_ins (cfg
, dest_sreg2
, ins
->sreg2
, NULL
, ip
, FALSE
);
1180 insert_before_ins (ins
, tmp
, copy
);
1183 DEBUG (printf ("\tshortcut assignment of R%d to %s\n", ins
->sreg2
, mono_arch_regname (dest_sreg2
)));
1184 assign_ireg (cfg
, rs
, ins
->sreg2
, dest_sreg2
);
1187 int need_spill
= TRUE
;
1189 dreg_mask
&= ~ (regmask (dest_sreg2
));
1190 sreg1_mask
&= ~ (regmask (dest_sreg2
));
1193 * First check if dreg is assigned to dest_sreg2, since we
1194 * can't spill a dreg.
1196 val
= rs
->iassign
[ins
->dreg
];
1197 if (val
== dest_sreg2
&& ins
->dreg
!= ins
->sreg2
) {
1199 * the destination register is already assigned to
1200 * dest_sreg2: we need to allocate another register for it
1201 * and then copy from this to dest_sreg2.
1204 new_dest
= alloc_int_reg (cfg
, tmp
, ins
, dreg_mask
, ins
->dreg
, ®info
[ins
->dreg
]);
1205 g_assert (new_dest
>= 0);
1206 DEBUG (printf ("\tchanging dreg R%d to %s from %s\n", ins
->dreg
, mono_arch_regname (new_dest
), mono_arch_regname (dest_sreg2
)));
1208 prev_dreg
= ins
->dreg
;
1209 assign_ireg (cfg
, rs
, ins
->dreg
, new_dest
);
1210 clob_dreg
= ins
->dreg
;
1211 create_copy_ins (cfg
, dest_sreg2
, new_dest
, ins
, ip
, FALSE
);
1212 mono_regstate_free_int (rs
, dest_sreg2
);
1216 if (is_global_ireg (ins
->sreg2
)) {
1217 MonoInst
*copy
= create_copy_ins (cfg
, dest_sreg2
, ins
->sreg2
, NULL
, ip
, FALSE
);
1218 insert_before_ins (ins
, tmp
, copy
);
1221 val
= rs
->iassign
[ins
->sreg2
];
1222 if (val
== dest_sreg2
) {
1223 /* sreg2 is already assigned to the correct register */
1226 else if ((val
>= 0) || (val
< -1)) {
1227 /* FIXME: sreg2 already assigned to another register */
1228 g_assert_not_reached ();
1233 DEBUG (printf ("\tforced spill of R%d\n", rs
->isymbolic
[dest_sreg2
]));
1234 get_register_force_spilling (cfg
, tmp
, ins
, rs
->isymbolic
[dest_sreg2
], FALSE
);
1235 mono_regstate2_free_int (rs
, dest_sreg2
);
1238 if (!is_global_ireg (ins
->sreg2
))
1239 /* force-set sreg2 */
1240 assign_ireg (cfg
, rs
, ins
->sreg2
, dest_sreg2
);
1242 ins
->sreg2
= dest_sreg2
;
1248 fp
= dreg_is_fp (spec
);
1249 if (spec
[MONO_INST_DEST
] && (!fp
|| (fp
&& !use_fpstack
)) && is_soft_reg (ins
->dreg
, fp
))
1250 prev_dreg
= ins
->dreg
;
1252 if (spec
[MONO_INST_DEST
] == 'b') {
1254 * The dest reg is read by the instruction, not written, so
1255 * avoid allocating sreg1/sreg2 to the same reg.
1257 if (dest_sreg1
!= -1)
1258 dreg_mask
&= ~ (regmask (dest_sreg1
));
1259 if (dest_sreg2
!= -1)
1260 dreg_mask
&= ~ (regmask (dest_sreg2
));
1262 val
= rassign (cfg
, ins
->dreg
, fp
);
1263 if (is_soft_reg (ins
->dreg
, fp
) && (val
>= 0) && (!(regmask (val
) & dreg_mask
))) {
1264 /* DREG is already allocated to a register needed for sreg1 */
1265 get_register_force_spilling (cfg
, tmp
, ins
, ins
->dreg
, FALSE
);
1266 mono_regstate2_free_int (rs
, val
);
1271 * If dreg is a fixed regpair, free up both of the needed hregs to avoid
1272 * various complex situations.
1274 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_DEST
])) {
1275 guint32 dreg2
, dest_dreg2
;
1277 g_assert (is_soft_reg (ins
->dreg
, fp
));
1279 if (dest_dreg
!= -1) {
1280 if (rs
->iassign
[ins
->dreg
] != dest_dreg
)
1281 free_up_ireg (cfg
, tmp
, ins
, dest_dreg
);
1283 dreg2
= ins
->dreg
+ 1;
1284 dest_dreg2
= MONO_ARCH_INST_REGPAIR_REG2 (spec
[MONO_INST_DEST
], dest_dreg
);
1285 if (dest_dreg2
!= -1) {
1286 if (rs
->iassign
[dreg2
] != dest_dreg2
)
1287 free_up_ireg (cfg
, tmp
, ins
, dest_dreg2
);
1292 if (dreg_fixed_mask
) {
1294 if (is_global_ireg (ins
->dreg
)) {
1296 * The argument is already in a hard reg, but that reg is
1297 * not usable by this instruction, so allocate a new one.
1299 val
= mono_regstate2_alloc_int (rs
, dreg_fixed_mask
);
1301 val
= get_register_spilling (cfg
, tmp
, ins
, dreg_fixed_mask
, -1, fp
);
1302 mono_regstate2_free_int (rs
, val
);
1308 dreg_mask
&= dreg_fixed_mask
;
1311 if ((!fp
|| (fp
&& !use_fpstack
)) && (is_soft_reg (ins
->dreg
, fp
))) {
1312 if (dest_dreg
!= -1)
1313 dreg_mask
= (regmask (dest_dreg
));
1315 val
= rassign (cfg
, ins
->dreg
, fp
);
1320 /* the register gets spilled after this inst */
1323 val
= alloc_reg (cfg
, tmp
, ins
, dreg_mask
, ins
->dreg
, ®info
[ins
->dreg
], fp
);
1324 assign_reg (cfg
, rs
, ins
->dreg
, val
, fp
);
1326 create_spilled_store (cfg
, spill
, val
, prev_dreg
, ins
, fp
);
1329 DEBUG (printf ("\tassigned dreg %s to dest R%d\n", mono_regname_full (val
, fp
), ins
->dreg
));
1333 /* Handle regpairs */
1334 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_DEST
])) {
1335 int reg2
= prev_dreg
+ 1;
1338 g_assert (prev_dreg
> -1);
1339 g_assert (!is_global_ireg (rs
->iassign
[prev_dreg
]));
1340 mask
= regpair_reg2_mask (spec
[MONO_INST_DEST
], rs
->iassign
[prev_dreg
]);
1341 val
= rs
->iassign
[reg2
];
1345 /* the register gets spilled after this inst */
1348 val
= mono_regstate2_alloc_int (rs
, mask
);
1350 val
= get_register_spilling (cfg
, tmp
, ins
, mask
, reg2
, fp
);
1352 create_spilled_store (cfg
, spill
, val
, reg2
, ins
, fp
);
1355 if (! (mask
& (regmask (val
)))) {
1356 val
= mono_regstate2_alloc_int (rs
, mask
);
1358 val
= get_register_spilling (cfg
, tmp
, ins
, mask
, reg2
, fp
);
1360 /* Reallocate hreg to the correct register */
1361 create_copy_ins (cfg
, rs
->iassign
[reg2
], val
, ins
, ip
, fp
);
1363 mono_regstate2_free_int (rs
, rs
->iassign
[reg2
]);
1367 DEBUG (printf ("\tassigned dreg-high %s to dest R%d\n", mono_arch_regname (val
), reg2
));
1368 assign_reg (cfg
, rs
, reg2
, val
, fp
);
1371 ins
->backend
.reg3
= val
;
1373 if (reg_is_freeable (val
, fp
) && reg2
>= 0 && (reginfo
[reg2
].born_in
>= i
)) {
1374 DEBUG (printf ("\tfreeable %s (R%d)\n", mono_arch_regname (val
), reg2
));
1375 mono_regstate2_free_int (rs
, val
);
1379 if ((!fp
|| (fp
&& !use_fpstack
)) && prev_dreg
>= 0 && is_soft_reg (prev_dreg
, fp
) && (fp
? reginfof
: reginfo
) [prev_dreg
].born_in
>= i
) {
1381 * In theory, we could free up the hreg even if the vreg is alive,
1382 * but branches inside bblocks force us to assign the same hreg
1383 * to a vreg every time it is encountered.
1385 int dreg
= rassign (cfg
, prev_dreg
, fp
);
1386 g_assert (dreg
>= 0);
1387 DEBUG (printf ("\tfreeable %s (R%d) (born in %d)\n", mono_regname_full (dreg
, fp
), prev_dreg
, (fp
? reginfof
: reginfo
) [prev_dreg
].born_in
));
1389 mono_regstate2_free_float (rs
, dreg
);
1391 mono_regstate2_free_int (rs
, dreg
);
1394 if ((dest_dreg
!= -1) && (ins
->dreg
!= dest_dreg
)) {
1395 /* this instruction only outputs to dest_dreg, need to copy */
1396 create_copy_ins (cfg
, ins
->dreg
, dest_dreg
, ins
, ip
, fp
);
1397 ins
->dreg
= dest_dreg
;
1400 if (rs
->fsymbolic
[dest_dreg
] >= MONO_MAX_FREGS
)
1401 free_up_reg (cfg
, tmp
, ins
, dest_dreg
, fp
);
1404 if (rs
->isymbolic
[dest_dreg
] >= MONO_MAX_IREGS
)
1405 free_up_reg (cfg
, tmp
, ins
, dest_dreg
, fp
);
1409 if (spec
[MONO_INST_DEST
] == 'b') {
1411 * The dest reg is read by the instruction, not written, so
1412 * avoid allocating sreg1/sreg2 to the same reg.
1414 sreg1_mask
&= ~ (regmask (ins
->dreg
));
1415 sreg2_mask
&= ~ (regmask (ins
->dreg
));
1421 if ((clob_reg
!= -1) && (!(rs
->ifree_mask
& (regmask (clob_reg
))))) {
1422 DEBUG (printf ("\tforced spill of clobbered reg R%d\n", rs
->isymbolic
[clob_reg
]));
1423 get_register_force_spilling (cfg
, tmp
, ins
, rs
->isymbolic
[clob_reg
], FALSE
);
1424 mono_regstate2_free_int (rs
, clob_reg
);
1427 if (spec
[MONO_INST_CLOB
] == 'c') {
1428 int j
, s
, dreg
, dreg2
;
1431 clob_mask
= MONO_ARCH_CALLEE_REGS
;
1434 * Need to avoid spilling the dreg since the dreg is not really
1435 * clobbered by the call.
1437 if ((prev_dreg
!= -1) && !dreg_is_fp (spec
))
1438 dreg
= rassign (cfg
, prev_dreg
, dreg_is_fp (spec
));
1442 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_DEST
]))
1443 dreg2
= rassign (cfg
, prev_dreg
+ 1, dreg_is_fp (spec
));
1447 for (j
= 0; j
< MONO_MAX_IREGS
; ++j
) {
1449 if ((clob_mask
& s
) && !(rs
->ifree_mask
& s
) && (j
!= ins
->sreg1
) && (j
!= dreg
) && (j
!= dreg2
)) {
1450 get_register_force_spilling (cfg
, tmp
, ins
, rs
->isymbolic
[j
], FALSE
);
1451 mono_regstate2_free_int (rs
, j
);
1456 clob_mask
= MONO_ARCH_CALLEE_FREGS
;
1457 if ((prev_dreg
!= -1) && dreg_is_fp (spec
))
1458 dreg
= rassign (cfg
, prev_dreg
, dreg_is_fp (spec
));
1462 for (j
= 0; j
< MONO_MAX_FREGS
; ++j
) {
1464 if ((clob_mask
& s
) && !(rs
->ffree_mask
& s
) && (j
!= ins
->sreg1
) && (j
!= dreg
)) {
1465 get_register_force_spilling (cfg
, tmp
, ins
, rs
->fsymbolic
[j
], TRUE
);
1466 mono_regstate2_free_float (rs
, j
);
1473 * TRACK ARGUMENT REGS
1475 if (spec
[MONO_INST_CLOB
] == 'c') {
1476 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1480 * This needs to be done before assigning sreg1, so sreg1 will
1481 * not be assigned one of the argument regs.
1485 * Assign all registers in call->out_reg_args to the proper
1486 * argument registers.
1489 list
= call
->out_ireg_args
;
1495 regpair
= (guint32
)(gssize
)(list
->data
);
1496 hreg
= regpair
>> 24;
1497 reg
= regpair
& 0xffffff;
1499 assign_reg (cfg
, rs
, reg
, hreg
, FALSE
);
1501 sreg1_mask
&= ~(regmask (hreg
));
1503 DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_regname (hreg
), reg
));
1505 list
= g_slist_next (list
);
1509 list
= call
->out_freg_args
;
1510 if (list
&& !use_fpstack
) {
1515 regpair
= (guint32
)(gssize
)(list
->data
);
1516 hreg
= regpair
>> 24;
1517 reg
= regpair
& 0xffffff;
1519 assign_reg (cfg
, rs
, reg
, hreg
, TRUE
);
1521 DEBUG (printf ("\tassigned arg reg %s to R%d\n", mono_arch_fregname (hreg
), reg
));
1523 list
= g_slist_next (list
);
1531 fp
= sreg1_is_fp (spec
);
1532 if ((!fp
|| (fp
&& !use_fpstack
))) {
1533 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_DEST
]) && (spec
[MONO_INST_CLOB
] == '1')) {
1534 g_assert (is_soft_reg (ins
->sreg1
, fp
));
1536 /* To simplify things, we allocate the same regpair to sreg1 and dreg */
1537 if (dest_sreg1
!= -1)
1538 g_assert (dest_sreg1
== ins
->dreg
);
1539 val
= mono_regstate2_alloc_int (rs
, regmask (ins
->dreg
));
1540 g_assert (val
>= 0);
1541 assign_reg (cfg
, rs
, ins
->sreg1
, val
, fp
);
1543 DEBUG (printf ("\tassigned sreg1-low %s to R%d\n", mono_regname_full (val
, fp
), ins
->sreg1
));
1545 g_assert ((regmask (dreg_high
)) & regpair_reg2_mask (spec
[MONO_INST_SRC1
], ins
->dreg
));
1546 val
= mono_regstate2_alloc_int (rs
, regmask (dreg_high
));
1547 g_assert (val
>= 0);
1548 assign_reg (cfg
, rs
, ins
->sreg1
+ 1, val
, fp
);
1550 DEBUG (printf ("\tassigned sreg1-high %s to R%d\n", mono_regname_full (val
, fp
), ins
->sreg1
+ 1));
1552 /* Skip rest of this section */
1556 if (sreg1_fixed_mask
) {
1558 if (is_global_ireg (ins
->sreg1
)) {
1560 * The argument is already in a hard reg, but that reg is
1561 * not usable by this instruction, so allocate a new one.
1563 val
= mono_regstate2_alloc_int (rs
, sreg1_fixed_mask
);
1565 val
= get_register_spilling (cfg
, tmp
, ins
, sreg1_fixed_mask
, -1, fp
);
1566 mono_regstate2_free_int (rs
, val
);
1569 /* Fall through to the dest_sreg1 != -1 case */
1572 sreg1_mask
&= sreg1_fixed_mask
;
1575 if (dest_sreg1
!= -1) {
1576 sreg1_mask
= regmask (dest_sreg1
);
1578 if (!(rs
->ifree_mask
& (regmask (dest_sreg1
)))) {
1579 DEBUG (printf ("\tforced spill of R%d\n", rs
->isymbolic
[dest_sreg1
]));
1580 get_register_force_spilling (cfg
, tmp
, ins
, rs
->isymbolic
[dest_sreg1
], FALSE
);
1581 mono_regstate2_free_int (rs
, dest_sreg1
);
1583 if (is_global_ireg (ins
->sreg1
)) {
1584 /* The argument is already in a hard reg, need to copy */
1585 MonoInst
*copy
= create_copy_ins (cfg
, dest_sreg1
, ins
->sreg1
, NULL
, ip
, FALSE
);
1586 insert_before_ins (ins
, tmp
, copy
);
1587 ins
->sreg1
= dest_sreg1
;
1591 if (is_soft_reg (ins
->sreg1
, fp
)) {
1592 val
= rassign (cfg
, ins
->sreg1
, fp
);
1593 prev_sreg1
= ins
->sreg1
;
1597 /* the register gets spilled after this inst */
1601 if (((ins
->opcode
== OP_MOVE
) || (ins
->opcode
== OP_SETREG
)) && !spill
&& !fp
&& (is_local_ireg (ins
->dreg
) && (rs
->ifree_mask
& (regmask (ins
->dreg
))))) {
1603 * Allocate the same hreg to sreg1 as well so the
1604 * peephole can get rid of the move.
1606 sreg1_mask
= regmask (ins
->dreg
);
1609 val
= alloc_reg (cfg
, tmp
, ins
, sreg1_mask
, ins
->sreg1
, ®info
[ins
->sreg1
], fp
);
1610 assign_reg (cfg
, rs
, ins
->sreg1
, val
, fp
);
1611 DEBUG (printf ("\tassigned sreg1 %s to R%d\n", mono_regname_full (val
, fp
), ins
->sreg1
));
1614 MonoInst
*store
= create_spilled_store (cfg
, spill
, val
, prev_sreg1
, NULL
, fp
);
1616 * Need to insert before the instruction since it can
1619 insert_before_ins (ins
, tmp
, store
);
1622 else if ((dest_sreg1
!= -1) && (dest_sreg1
!= val
)) {
1623 create_copy_ins (cfg
, dest_sreg1
, val
, ins
, ip
, fp
);
1631 sreg2_mask
&= ~(regmask (ins
->sreg1
));
1634 /* Handle the case when sreg1 is a regpair but dreg is not */
1635 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_SRC1
]) && (spec
[MONO_INST_CLOB
] != '1')) {
1636 int reg2
= prev_sreg1
+ 1;
1639 g_assert (prev_sreg1
> -1);
1640 g_assert (!is_global_ireg (rs
->iassign
[prev_sreg1
]));
1641 mask
= regpair_reg2_mask (spec
[MONO_INST_SRC1
], rs
->iassign
[prev_sreg1
]);
1642 val
= rs
->iassign
[reg2
];
1646 /* the register gets spilled after this inst */
1649 val
= mono_regstate2_alloc_int (rs
, mask
);
1651 val
= get_register_spilling (cfg
, tmp
, ins
, mask
, reg2
, fp
);
1653 g_assert_not_reached ();
1656 if (! (mask
& (regmask (val
)))) {
1657 /* The vreg is already allocated to a wrong hreg */
1659 g_assert_not_reached ();
1661 val
= mono_regstate2_alloc_int (rs
, mask
);
1663 val
= get_register_spilling (cfg
, tmp
, ins
, mask
, reg2
, fp
);
1665 /* Reallocate hreg to the correct register */
1666 create_copy_ins (cfg
, rs
->iassign
[reg2
], val
, ins
, ip
, fp
);
1668 mono_regstate2_free_int (rs
, rs
->iassign
[reg2
]);
1674 DEBUG (printf ("\tassigned sreg1 hreg %s to dest R%d\n", mono_arch_regname (val
), reg2
));
1675 assign_reg (cfg
, rs
, reg2
, val
, fp
);
1678 /* Handle dreg==sreg1 */
1679 if (((dreg_is_fp (spec
) && spec
[MONO_INST_SRC1
] == 'f' && !use_fpstack
) || spec
[MONO_INST_CLOB
] == '1') && ins
->dreg
!= ins
->sreg1
) {
1680 MonoInst
*sreg2_copy
= NULL
;
1682 gboolean fp
= (spec
[MONO_INST_SRC1
] == 'f');
1684 if (ins
->dreg
== ins
->sreg2
) {
1686 * copying sreg1 to dreg could clobber sreg2, so allocate a new
1689 int reg2
= alloc_reg (cfg
, tmp
, ins
, dreg_mask
, ins
->sreg2
, NULL
, fp
);
1691 DEBUG (printf ("\tneed to copy sreg2 %s to reg %s\n", mono_regname_full (ins
->sreg2
, fp
), mono_regname_full (reg2
, fp
)));
1692 sreg2_copy
= create_copy_ins (cfg
, reg2
, ins
->sreg2
, NULL
, ip
, fp
);
1693 prev_sreg2
= ins
->sreg2
= reg2
;
1696 mono_regstate2_free_float (rs
, reg2
);
1698 mono_regstate2_free_int (rs
, reg2
);
1701 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_SRC1
])) {
1702 /* Copying sreg1_high to dreg could also clobber sreg2 */
1703 if (rs
->iassign
[prev_sreg1
+ 1] == ins
->sreg2
)
1705 g_assert_not_reached ();
1708 * sreg1 and dest are already allocated to the same regpair by the
1709 * SREG1 allocation code.
1711 g_assert (ins
->sreg1
== ins
->dreg
);
1712 g_assert (dreg_high
== sreg1_high
);
1715 DEBUG (printf ("\tneed to copy sreg1 %s to dreg %s\n", mono_regname_full (ins
->sreg1
, fp
), mono_regname_full (ins
->dreg
, fp
)));
1716 copy
= create_copy_ins (cfg
, ins
->dreg
, ins
->sreg1
, NULL
, ip
, fp
);
1717 insert_before_ins (ins
, tmp
, copy
);
1720 insert_before_ins (copy
, tmp
, sreg2_copy
);
1723 * Need to prevent sreg2 to be allocated to sreg1, since that
1724 * would screw up the previous copy.
1726 sreg2_mask
&= ~ (regmask (ins
->sreg1
));
1727 /* we set sreg1 to dest as well */
1728 prev_sreg1
= ins
->sreg1
= ins
->dreg
;
1729 sreg2_mask
&= ~ (regmask (ins
->dreg
));
1735 fp
= sreg2_is_fp (spec
);
1736 if (MONO_ARCH_INST_IS_REGPAIR (spec
[MONO_INST_SRC2
]))
1737 g_assert_not_reached ();
1738 if ((!fp
|| (fp
&& !use_fpstack
)) && (is_soft_reg (ins
->sreg2
, fp
))) {
1739 val
= rassign (cfg
, ins
->sreg2
, fp
);
1744 /* the register gets spilled after this inst */
1747 val
= alloc_reg (cfg
, tmp
, ins
, sreg2_mask
, ins
->sreg2
, ®info
[ins
->sreg2
], fp
);
1748 assign_reg (cfg
, rs
, ins
->sreg2
, val
, fp
);
1749 DEBUG (printf ("\tassigned sreg2 %s to R%d\n", mono_regname_full (val
, fp
), ins
->sreg2
));
1751 MonoInst
*store
= create_spilled_store (cfg
, spill
, val
, prev_sreg2
, NULL
, fp
);
1753 * Need to insert before the instruction since it can
1756 insert_before_ins (ins
, tmp
, store
);
1765 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
1766 DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg1)));
1767 mono_regstate2_free_int (rs, ins->sreg1);
1769 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
1770 DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg2)));
1771 mono_regstate2_free_int (rs, ins->sreg2);
1774 DEBUG (print_ins (i
, ins
));
1775 /* this may result from a insert_before call */
1777 bb
->code
= tmp
->data
;
1781 g_list_free (fspill_list
);