2 * alias-analysis.c: Implement simple alias analysis for local variables.
5 * Rodrigo Kumpera (kumpera@gmail.com)
20 is_int_stack_size (int type)
22 #if SIZEOF_VOID_P == 4
23 return type == STACK_I4 || type == STACK_MP;
25 return type == STACK_I4;
30 is_long_stack_size (int type)
32 #if SIZEOF_VOID_P == 8
33 return type == STACK_I8 || type == STACK_MP;
35 return type == STACK_I8;
41 lower_load (MonoCompile *cfg, MonoInst *load, MonoInst *ldaddr)
43 MonoInst *var = (MonoInst *)ldaddr->inst_p0;
44 MonoType *type = &var->klass->byval_arg;
45 int replaced_op = mono_type_to_load_membase (cfg, type);
47 if (load->opcode == OP_LOADV_MEMBASE && load->klass != var->klass) {
48 if (cfg->verbose_level > 2)
49 printf ("Incompatible load_vtype classes %s x %s\n", load->klass->name, var->klass->name);
53 if (replaced_op != load->opcode) {
54 if (cfg->verbose_level > 2)
55 printf ("Incompatible load type: expected %s but got %s\n",
56 mono_inst_name (replaced_op),
57 mono_inst_name (load->opcode));
60 if (cfg->verbose_level > 2) { printf ("mem2reg replacing: "); mono_print_ins (load); }
63 load->opcode = mono_type_to_regmove (cfg, type);
64 type_to_eval_stack_type (cfg, type, load);
65 load->sreg1 = var->dreg;
66 mono_jit_stats.loads_eliminated++;
71 lower_store (MonoCompile *cfg, MonoInst *store, MonoInst *ldaddr)
73 MonoInst *var = (MonoInst *)ldaddr->inst_p0;
74 MonoType *type = &var->klass->byval_arg;
75 int replaced_op = mono_type_to_store_membase (cfg, type);
77 if (store->opcode == OP_STOREV_MEMBASE && store->klass != var->klass) {
78 if (cfg->verbose_level > 2)
79 printf ("Incompatible store_vtype classes %s x %s\n", store->klass->name, store->klass->name);
84 if (replaced_op != store->opcode) {
85 if (cfg->verbose_level > 2)
86 printf ("Incompatible store_reg type: expected %s but got %s\n",
87 mono_inst_name (replaced_op),
88 mono_inst_name (store->opcode));
91 if (cfg->verbose_level > 2) { printf ("mem2reg replacing: "); mono_print_ins (store); }
94 store->opcode = mono_type_to_regmove (cfg, type);
95 type_to_eval_stack_type (cfg, type, store);
96 store->dreg = var->dreg;
97 mono_jit_stats.stores_eliminated++;
102 lower_store_imm (MonoCompile *cfg, MonoInst *store, MonoInst *ldaddr)
104 MonoInst *var = (MonoInst *)ldaddr->inst_p0;
105 MonoType *type = &var->klass->byval_arg;
106 int store_op = mono_type_to_store_membase (cfg, type);
107 if (store_op == OP_STOREV_MEMBASE || store_op == OP_STOREX_MEMBASE)
110 switch (store->opcode) {
111 #if SIZEOF_VOID_P == 4
112 case OP_STORE_MEMBASE_IMM:
114 case OP_STOREI4_MEMBASE_IMM:
115 if (!is_int_stack_size (var->type)) {
116 if (cfg->verbose_level > 2) printf ("Incompatible variable of size != 4\n");
119 if (cfg->verbose_level > 2) { printf ("mem2reg replacing: "); mono_print_ins (store); }
120 store->opcode = OP_ICONST;
121 store->type = STACK_I4;
122 store->dreg = var->dreg;
123 store->inst_c0 = store->inst_imm;
126 #if SIZEOF_VOID_P == 8
127 case OP_STORE_MEMBASE_IMM:
129 case OP_STOREI8_MEMBASE_IMM:
130 if (!is_long_stack_size (var->type)) {
131 if (cfg->verbose_level > 2) printf ("Incompatible variable of size != 8\n");
134 if (cfg->verbose_level > 2) { printf ("mem2reg replacing: "); mono_print_ins (store); }
135 store->opcode = OP_I8CONST;
136 store->type = STACK_I8;
137 store->dreg = var->dreg;
138 store->inst_l = store->inst_imm;
143 mono_jit_stats.stores_eliminated++;
148 lower_memory_access (MonoCompile *cfg)
152 gboolean needs_dce = FALSE;
153 GHashTable *addr_loads = g_hash_table_new (NULL, NULL);
155 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
156 g_hash_table_remove_all (addr_loads);
158 for (ins = bb->code; ins; ins = ins->next) {
160 switch (ins->opcode) {
162 g_hash_table_insert (addr_loads, GINT_TO_POINTER (ins->dreg), ins);
163 if (cfg->verbose_level > 2) { printf ("New address: "); mono_print_ins (ins); }
166 tmp = (MonoInst*)g_hash_table_lookup (addr_loads, GINT_TO_POINTER (ins->sreg1));
168 Forward propagate known aliases
173 g_hash_table_insert (addr_loads, GINT_TO_POINTER (ins->dreg), tmp);
174 if (cfg->verbose_level > 2) { printf ("New alias: "); mono_print_ins (ins); }
177 Source value is not a know address, kill the variable.
179 if (g_hash_table_remove (addr_loads, GINT_TO_POINTER (ins->dreg))) {
180 if (cfg->verbose_level > 2) { printf ("Killed alias: "); mono_print_ins (ins); }
185 case OP_LOADV_MEMBASE:
186 case OP_LOAD_MEMBASE:
187 case OP_LOADU1_MEMBASE:
188 case OP_LOADI2_MEMBASE:
189 case OP_LOADU2_MEMBASE:
190 case OP_LOADI4_MEMBASE:
191 case OP_LOADU4_MEMBASE:
192 case OP_LOADI1_MEMBASE:
193 case OP_LOADI8_MEMBASE:
194 #ifndef MONO_ARCH_SOFT_FLOAT_FALLBACK
195 case OP_LOADR4_MEMBASE:
197 case OP_LOADR8_MEMBASE:
198 if (ins->inst_offset != 0)
200 tmp = (MonoInst *)g_hash_table_lookup (addr_loads, GINT_TO_POINTER (ins->sreg1));
202 if (cfg->verbose_level > 2) { printf ("Found candidate load:"); mono_print_ins (ins); }
203 if (lower_load (cfg, ins, tmp)) {
205 /* Try to propagate known aliases if an OP_MOVE was inserted */
206 goto handle_instruction;
211 case OP_STORE_MEMBASE_REG:
212 case OP_STOREI1_MEMBASE_REG:
213 case OP_STOREI2_MEMBASE_REG:
214 case OP_STOREI4_MEMBASE_REG:
215 case OP_STOREI8_MEMBASE_REG:
216 #ifndef MONO_ARCH_SOFT_FLOAT_FALLBACK
217 case OP_STORER4_MEMBASE_REG:
219 case OP_STORER8_MEMBASE_REG:
220 case OP_STOREV_MEMBASE:
221 if (ins->inst_offset != 0)
223 tmp = (MonoInst *)g_hash_table_lookup (addr_loads, GINT_TO_POINTER (ins->dreg));
225 if (cfg->verbose_level > 2) { printf ("Found candidate store:"); mono_print_ins (ins); }
226 if (lower_store (cfg, ins, tmp)) {
228 /* Try to propagate known aliases if an OP_MOVE was inserted */
229 goto handle_instruction;
233 //FIXME missing storei1_membase_imm and storei2_membase_imm
234 case OP_STORE_MEMBASE_IMM:
235 case OP_STOREI4_MEMBASE_IMM:
236 case OP_STOREI8_MEMBASE_IMM:
237 if (ins->inst_offset != 0)
239 tmp = (MonoInst *)g_hash_table_lookup (addr_loads, GINT_TO_POINTER (ins->dreg));
241 if (cfg->verbose_level > 2) { printf ("Found candidate store-imm:"); mono_print_ins (ins); }
242 needs_dce |= lower_store_imm (cfg, ins, tmp);
247 tmp = (MonoInst *)g_hash_table_lookup (addr_loads, GINT_TO_POINTER (ins->sreg1));
249 if (cfg->verbose_level > 2) { printf ("Found null check over local: "); mono_print_ins (ins); }
257 g_hash_table_destroy (addr_loads);
262 recompute_aliased_variables (MonoCompile *cfg, int *restored_vars)
271 for (i = 0; i < cfg->num_varinfo; i++) {
272 MonoInst *var = cfg->varinfo [i];
273 if (var->flags & MONO_INST_INDIRECT) {
274 if (cfg->verbose_level > 2) {
275 printf ("Killing :"); mono_print_ins (var);
279 var->flags &= ~MONO_INST_INDIRECT;
285 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
286 for (ins = bb->code; ins; ins = ins->next) {
287 if (ins->opcode == OP_LDADDR) {
290 if (cfg->verbose_level > 2) { printf ("Found op :"); mono_print_ins (ins); }
292 var = (MonoInst*)ins->inst_p0;
293 if (!(var->flags & MONO_INST_INDIRECT)) {
294 if (cfg->verbose_level > 1) { printf ("Restoring :"); mono_print_ins (var); }
297 var->flags |= MONO_INST_INDIRECT;
301 *restored_vars = adds;
303 mono_jit_stats.alias_found += kills;
304 mono_jit_stats.alias_removed += kills - adds;
306 if (cfg->verbose_level > 2) {
307 printf ("Method: %s\n", mono_method_full_name (cfg->method, 1));
308 printf ("Kills %d Adds %d\n", kills, adds);
317 Don't DCE on the whole CFG, only the BBs that have changed.
320 SRVT of small types can fix cases of mismatch for fields of a different type than the component.
321 Handle aliasing of byrefs in call conventions.
324 mono_local_alias_analysis (MonoCompile *cfg)
326 int i, restored_vars = 1;
327 if (!cfg->has_indirection)
330 if (cfg->verbose_level > 2)
331 mono_print_code (cfg, "BEFORE ALIAS_ANALYSIS");
334 Remove indirection and memory access of known variables.
336 if (!lower_memory_access (cfg))
340 By replacing indirect access with direct operations, some LDADDR ops become dead. Kill them.
342 if (cfg->opt & MONO_OPT_DEADCE)
343 mono_local_deadce (cfg);
346 Some variables no longer need to be flagged as indirect, find them.
347 Since indirect vars are converted into global vregs, each pass eliminates only one level of indirection.
348 Most cases only need one pass and some 2.
350 for (i = 0; i < 3 && restored_vars > 0 && recompute_aliased_variables (cfg, &restored_vars); ++i) {
352 A lot of simplification just took place, we recompute local variables and do DCE to
353 really profit from the previous gains
355 mono_handle_global_vregs (cfg);
356 if (cfg->opt & MONO_OPT_DEADCE)
357 mono_local_deadce (cfg);
361 if (cfg->verbose_level > 2)
362 mono_print_code (cfg, "AFTER ALIAS_ANALYSIS");
365 #endif /* !DISABLE_JIT */