3 * Implement simple alias analysis for local variables.
6 * Rodrigo Kumpera (kumpera@gmail.com)
17 #include <mono/utils/mono-compiler.h>
22 is_int_stack_size (int type
)
24 #if TARGET_SIZEOF_VOID_P == 4
25 return type
== STACK_I4
|| type
== STACK_MP
;
27 return type
== STACK_I4
;
32 is_long_stack_size (int type
)
34 #if TARGET_SIZEOF_VOID_P == 8
35 return type
== STACK_I8
|| type
== STACK_MP
;
37 return type
== STACK_I8
;
43 lower_load (MonoCompile
*cfg
, MonoInst
*load
, MonoInst
*ldaddr
)
45 MonoInst
*var
= (MonoInst
*)ldaddr
->inst_p0
;
46 MonoType
*type
= m_class_get_byval_arg (var
->klass
);
47 int replaced_op
= mono_type_to_load_membase (cfg
, type
);
49 if (load
->opcode
== OP_LOADV_MEMBASE
&& load
->klass
!= var
->klass
) {
50 if (cfg
->verbose_level
> 2)
51 printf ("Incompatible load_vtype classes %s x %s\n", m_class_get_name (load
->klass
), m_class_get_name (var
->klass
));
55 if (replaced_op
!= load
->opcode
) {
56 if (cfg
->verbose_level
> 2)
57 printf ("Incompatible load type: expected %s but got %s\n",
58 mono_inst_name (replaced_op
),
59 mono_inst_name (load
->opcode
));
62 if (cfg
->verbose_level
> 2) { printf ("mem2reg replacing: "); mono_print_ins (load
); }
65 load
->opcode
= mono_type_to_regmove (cfg
, type
);
66 mini_type_to_eval_stack_type (cfg
, type
, load
);
67 load
->sreg1
= var
->dreg
;
68 mono_atomic_inc_i32 (&mono_jit_stats
.loads_eliminated
);
73 lower_store (MonoCompile
*cfg
, MonoInst
*store
, MonoInst
*ldaddr
)
75 MonoInst
*var
= (MonoInst
*)ldaddr
->inst_p0
;
76 MonoType
*type
= m_class_get_byval_arg (var
->klass
);
77 int replaced_op
= mono_type_to_store_membase (cfg
, type
);
79 if (store
->opcode
== OP_STOREV_MEMBASE
&& store
->klass
!= var
->klass
) {
80 if (cfg
->verbose_level
> 2)
81 printf ("Incompatible store_vtype classes %s x %s\n", m_class_get_name (store
->klass
), m_class_get_name (store
->klass
));
86 if (replaced_op
!= store
->opcode
) {
87 if (cfg
->verbose_level
> 2)
88 printf ("Incompatible store_reg type: expected %s but got %s\n",
89 mono_inst_name (replaced_op
),
90 mono_inst_name (store
->opcode
));
93 if (cfg
->verbose_level
> 2) { printf ("mem2reg replacing: "); mono_print_ins (store
); }
96 int coerce_op
= mono_type_to_stloc_coerce (type
);
98 store
->opcode
= coerce_op
;
100 store
->opcode
= mono_type_to_regmove (cfg
, type
);
101 mini_type_to_eval_stack_type (cfg
, type
, store
);
102 store
->dreg
= var
->dreg
;
103 mono_atomic_inc_i32 (&mono_jit_stats
.stores_eliminated
);
108 lower_store_imm (MonoCompile
*cfg
, MonoInst
*store
, MonoInst
*ldaddr
)
110 MonoInst
*var
= (MonoInst
*)ldaddr
->inst_p0
;
111 MonoType
*type
= m_class_get_byval_arg (var
->klass
);
112 int store_op
= mono_type_to_store_membase (cfg
, type
);
113 if (store_op
== OP_STOREV_MEMBASE
|| store_op
== OP_STOREX_MEMBASE
)
116 switch (store
->opcode
) {
117 #if TARGET_SIZEOF_VOID_P == 4
118 case OP_STORE_MEMBASE_IMM
:
120 case OP_STOREI4_MEMBASE_IMM
:
121 if (!is_int_stack_size (var
->type
)) {
122 if (cfg
->verbose_level
> 2) printf ("Incompatible variable of size != 4\n");
125 if (cfg
->verbose_level
> 2) { printf ("mem2reg replacing: "); mono_print_ins (store
); }
126 store
->opcode
= OP_ICONST
;
127 store
->type
= STACK_I4
;
128 store
->dreg
= var
->dreg
;
129 store
->inst_c0
= store
->inst_imm
;
132 #if TARGET_SIZEOF_VOID_P == 8
133 case OP_STORE_MEMBASE_IMM
:
135 case OP_STOREI8_MEMBASE_IMM
:
136 if (!is_long_stack_size (var
->type
)) {
137 if (cfg
->verbose_level
> 2) printf ("Incompatible variable of size != 8\n");
140 if (cfg
->verbose_level
> 2) { printf ("mem2reg replacing: "); mono_print_ins (store
); }
141 store
->opcode
= OP_I8CONST
;
142 store
->type
= STACK_I8
;
143 store
->dreg
= var
->dreg
;
144 store
->inst_l
= store
->inst_imm
;
149 mono_atomic_inc_i32 (&mono_jit_stats
.stores_eliminated
);
154 lower_memory_access (MonoCompile
*cfg
)
158 gboolean needs_dce
= FALSE
;
159 GHashTable
*addr_loads
= g_hash_table_new (NULL
, NULL
);
161 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
162 g_hash_table_remove_all (addr_loads
);
164 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
166 switch (ins
->opcode
) {
168 MonoInst
*var
= (MonoInst
*)ins
->inst_p0
;
169 if (var
->flags
& MONO_INST_VOLATILE
) {
170 if (cfg
->verbose_level
> 2) { printf ("Found address to volatile var, can't take it: "); mono_print_ins (ins
); }
172 g_hash_table_insert (addr_loads
, GINT_TO_POINTER (ins
->dreg
), ins
);
173 if (cfg
->verbose_level
> 2) { printf ("New address: "); mono_print_ins (ins
); }
179 tmp
= (MonoInst
*)g_hash_table_lookup (addr_loads
, GINT_TO_POINTER (ins
->sreg1
));
181 Forward propagate known aliases
186 g_hash_table_insert (addr_loads
, GINT_TO_POINTER (ins
->dreg
), tmp
);
187 if (cfg
->verbose_level
> 2) { printf ("New alias: "); mono_print_ins (ins
); }
190 Source value is not a know address, kill the variable.
192 if (g_hash_table_remove (addr_loads
, GINT_TO_POINTER (ins
->dreg
))) {
193 if (cfg
->verbose_level
> 2) { printf ("Killed alias: "); mono_print_ins (ins
); }
198 case OP_LOADV_MEMBASE
:
199 case OP_LOAD_MEMBASE
:
200 case OP_LOADU1_MEMBASE
:
201 case OP_LOADI2_MEMBASE
:
202 case OP_LOADU2_MEMBASE
:
203 case OP_LOADI4_MEMBASE
:
204 case OP_LOADU4_MEMBASE
:
205 case OP_LOADI1_MEMBASE
:
206 case OP_LOADI8_MEMBASE
:
207 #ifndef MONO_ARCH_SOFT_FLOAT_FALLBACK
208 case OP_LOADR4_MEMBASE
:
210 case OP_LOADR8_MEMBASE
:
211 if (ins
->inst_offset
!= 0)
213 tmp
= (MonoInst
*)g_hash_table_lookup (addr_loads
, GINT_TO_POINTER (ins
->sreg1
));
215 if (cfg
->verbose_level
> 2) { printf ("Found candidate load:"); mono_print_ins (ins
); }
216 if (lower_load (cfg
, ins
, tmp
)) {
218 /* Try to propagate known aliases if an OP_MOVE was inserted */
219 goto handle_instruction
;
224 case OP_STORE_MEMBASE_REG
:
225 case OP_STOREI1_MEMBASE_REG
:
226 case OP_STOREI2_MEMBASE_REG
:
227 case OP_STOREI4_MEMBASE_REG
:
228 case OP_STOREI8_MEMBASE_REG
:
229 #ifndef MONO_ARCH_SOFT_FLOAT_FALLBACK
230 case OP_STORER4_MEMBASE_REG
:
232 case OP_STORER8_MEMBASE_REG
:
233 case OP_STOREV_MEMBASE
:
234 if (ins
->inst_offset
!= 0)
236 tmp
= (MonoInst
*)g_hash_table_lookup (addr_loads
, GINT_TO_POINTER (ins
->dreg
));
238 if (cfg
->verbose_level
> 2) { printf ("Found candidate store:"); mono_print_ins (ins
); }
239 if (lower_store (cfg
, ins
, tmp
)) {
241 /* Try to propagate known aliases if an OP_MOVE was inserted */
242 goto handle_instruction
;
246 //FIXME missing storei1_membase_imm and storei2_membase_imm
247 case OP_STORE_MEMBASE_IMM
:
248 case OP_STOREI4_MEMBASE_IMM
:
249 case OP_STOREI8_MEMBASE_IMM
:
250 if (ins
->inst_offset
!= 0)
252 tmp
= (MonoInst
*)g_hash_table_lookup (addr_loads
, GINT_TO_POINTER (ins
->dreg
));
254 if (cfg
->verbose_level
> 2) { printf ("Found candidate store-imm:"); mono_print_ins (ins
); }
255 needs_dce
|= lower_store_imm (cfg
, ins
, tmp
);
260 tmp
= (MonoInst
*)g_hash_table_lookup (addr_loads
, GINT_TO_POINTER (ins
->sreg1
));
262 if (cfg
->verbose_level
> 2) { printf ("Found null check over local: "); mono_print_ins (ins
); }
270 g_hash_table_destroy (addr_loads
);
275 recompute_aliased_variables (MonoCompile
*cfg
, int *restored_vars
)
284 for (i
= 0; i
< cfg
->num_varinfo
; i
++) {
285 MonoInst
*var
= cfg
->varinfo
[i
];
286 if (var
->flags
& MONO_INST_INDIRECT
) {
287 if (cfg
->verbose_level
> 2) {
288 printf ("Killing :"); mono_print_ins (var
);
292 var
->flags
&= ~MONO_INST_INDIRECT
;
298 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
299 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
300 if (ins
->opcode
== OP_LDADDR
) {
303 if (cfg
->verbose_level
> 2) { printf ("Found op :"); mono_print_ins (ins
); }
305 var
= (MonoInst
*)ins
->inst_p0
;
306 if (!(var
->flags
& MONO_INST_INDIRECT
)) {
307 if (cfg
->verbose_level
> 1) { printf ("Restoring :"); mono_print_ins (var
); }
310 var
->flags
|= MONO_INST_INDIRECT
;
314 *restored_vars
= adds
;
316 mono_atomic_fetch_add_i32 (&mono_jit_stats
.alias_found
, kills
);
317 mono_atomic_fetch_add_i32 (&mono_jit_stats
.alias_removed
, kills
- adds
);
319 if (cfg
->verbose_level
> 2) {
320 printf ("Method: %s\n", mono_method_full_name (cfg
->method
, 1));
321 printf ("Kills %d Adds %d\n", kills
, adds
);
330 Don't DCE on the whole CFG, only the BBs that have changed.
333 SRVT of small types can fix cases of mismatch for fields of a different type than the component.
334 Handle aliasing of byrefs in call conventions.
337 mono_local_alias_analysis (MonoCompile
*cfg
)
339 int i
, restored_vars
= 1;
340 if (!cfg
->has_indirection
)
343 if (cfg
->verbose_level
> 2)
344 mono_print_code (cfg
, "BEFORE ALIAS_ANALYSIS");
347 Remove indirection and memory access of known variables.
349 if (!lower_memory_access (cfg
))
353 By replacing indirect access with direct operations, some LDADDR ops become dead. Kill them.
355 if (cfg
->opt
& MONO_OPT_DEADCE
)
356 mono_local_deadce (cfg
);
359 Some variables no longer need to be flagged as indirect, find them.
360 Since indirect vars are converted into global vregs, each pass eliminates only one level of indirection.
361 Most cases only need one pass and some 2.
363 for (i
= 0; i
< 3 && restored_vars
> 0 && recompute_aliased_variables (cfg
, &restored_vars
); ++i
) {
365 A lot of simplification just took place, we recompute local variables and do DCE to
366 really profit from the previous gains
368 mono_handle_global_vregs (cfg
);
369 if (cfg
->opt
& MONO_OPT_DEADCE
)
370 mono_local_deadce (cfg
);
374 if (cfg
->verbose_level
> 2)
375 mono_print_code (cfg
, "AFTER ALIAS_ANALYSIS");
378 #else /* !DISABLE_JIT */
380 MONO_EMPTY_SOURCE_FILE (alias_analysis
);
382 #endif /* !DISABLE_JIT */