2 * alias-analysis.c: Implement simple alias analysis for local variables.
5 * Rodrigo Kumpera (kumpera@gmail.com)
18 is_int_stack_size (int type)
20 #if SIZEOF_VOID_P == 4
21 return type == STACK_I4 || type == STACK_MP;
23 return type == STACK_I4;
28 is_long_stack_size (int type)
30 #if SIZEOF_VOID_P == 8
31 return type == STACK_I8 || type == STACK_MP;
33 return type == STACK_I8;
39 lower_load (MonoCompile *cfg, MonoInst *load, MonoInst *ldaddr)
41 MonoInst *var = ldaddr->inst_p0;
42 MonoType *type = &var->klass->byval_arg;
43 int replaced_op = mono_type_to_load_membase (cfg, type);
45 if (load->opcode == OP_LOADV_MEMBASE && load->klass != var->klass) {
46 if (cfg->verbose_level > 2)
47 printf ("Incompatible load_vtype classes %s x %s\n", load->klass->name, var->klass->name);
51 if (replaced_op != load->opcode) {
52 if (cfg->verbose_level > 2)
53 printf ("Incompatible load type: expected %s but got %s\n",
54 mono_inst_name (replaced_op),
55 mono_inst_name (load->opcode));
58 if (cfg->verbose_level > 2) { printf ("mem2reg replacing: "); mono_print_ins (load); }
61 load->opcode = mono_type_to_regmove (cfg, type);
62 type_to_eval_stack_type (cfg, type, load);
63 load->sreg1 = var->dreg;
64 mono_jit_stats.loads_eliminated++;
69 lower_store (MonoCompile *cfg, MonoInst *store, MonoInst *ldaddr)
71 MonoInst *var = ldaddr->inst_p0;
72 MonoType *type = &var->klass->byval_arg;
73 int replaced_op = mono_type_to_store_membase (cfg, type);
75 if (store->opcode == OP_STOREV_MEMBASE && store->klass != var->klass) {
76 if (cfg->verbose_level > 2)
77 printf ("Incompatible store_vtype classes %s x %s\n", store->klass->name, store->klass->name);
82 if (replaced_op != store->opcode) {
83 if (cfg->verbose_level > 2)
84 printf ("Incompatible store_reg type: expected %s but got %s\n",
85 mono_inst_name (replaced_op),
86 mono_inst_name (store->opcode));
89 if (cfg->verbose_level > 2) { printf ("mem2reg replacing: "); mono_print_ins (store); }
92 store->opcode = mono_type_to_regmove (cfg, type);
93 type_to_eval_stack_type (cfg, type, store);
94 store->dreg = var->dreg;
95 mono_jit_stats.stores_eliminated++;
100 lower_store_imm (MonoCompile *cfg, MonoInst *store, MonoInst *ldaddr)
102 MonoInst *var = ldaddr->inst_p0;
103 MonoType *type = &var->klass->byval_arg;
104 int store_op = mono_type_to_store_membase (cfg, type);
105 if (store_op == OP_STOREV_MEMBASE || store_op == OP_STOREX_MEMBASE)
108 switch (store->opcode) {
109 #if SIZEOF_VOID_P == 4
110 case OP_STORE_MEMBASE_IMM:
112 case OP_STOREI4_MEMBASE_IMM:
113 if (!is_int_stack_size (var->type)) {
114 if (cfg->verbose_level > 2) printf ("Incompatible variable of size != 4\n");
117 if (cfg->verbose_level > 2) { printf ("mem2reg replacing: "); mono_print_ins (store); }
118 store->opcode = OP_ICONST;
119 store->type = STACK_I4;
120 store->dreg = var->dreg;
121 store->inst_c0 = store->inst_imm;
124 #if SIZEOF_VOID_P == 8
125 case OP_STORE_MEMBASE_IMM:
127 case OP_STOREI8_MEMBASE_IMM:
128 if (!is_long_stack_size (var->type)) {
129 if (cfg->verbose_level > 2) printf ("Incompatible variable of size != 8\n");
132 if (cfg->verbose_level > 2) { printf ("mem2reg replacing: "); mono_print_ins (store); }
133 store->opcode = OP_I8CONST;
134 store->type = STACK_I8;
135 store->dreg = var->dreg;
136 store->inst_l = store->inst_imm;
141 mono_jit_stats.stores_eliminated++;
146 lower_memory_access (MonoCompile *cfg)
150 gboolean needs_dce = FALSE;
151 GHashTable *addr_loads = g_hash_table_new (NULL, NULL);
153 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
154 g_hash_table_remove_all (addr_loads);
156 for (ins = bb->code; ins; ins = ins->next) {
157 switch (ins->opcode) {
159 g_hash_table_insert (addr_loads, GINT_TO_POINTER (ins->dreg), ins);
160 if (cfg->verbose_level > 2) { printf ("New address: "); mono_print_ins (ins); }
163 tmp = (MonoInst*)g_hash_table_lookup (addr_loads, GINT_TO_POINTER (ins->sreg1));
165 Forward propagate known aliases
170 g_hash_table_insert (addr_loads, GINT_TO_POINTER (ins->dreg), tmp);
171 if (cfg->verbose_level > 2) { printf ("New alias: "); mono_print_ins (ins); }
174 Source value is not a know address, kill the variable.
176 if (g_hash_table_remove (addr_loads, GINT_TO_POINTER (ins->dreg))) {
177 if (cfg->verbose_level > 2) { printf ("Killed alias: "); mono_print_ins (ins); }
182 case OP_LOADV_MEMBASE:
183 case OP_LOAD_MEMBASE:
184 case OP_LOADU1_MEMBASE:
185 case OP_LOADI2_MEMBASE:
186 case OP_LOADU2_MEMBASE:
187 case OP_LOADI4_MEMBASE:
188 case OP_LOADU4_MEMBASE:
189 case OP_LOADI1_MEMBASE:
190 case OP_LOADI8_MEMBASE:
191 case OP_LOADR4_MEMBASE:
192 case OP_LOADR8_MEMBASE:
193 if (ins->inst_offset != 0)
195 tmp = g_hash_table_lookup (addr_loads, GINT_TO_POINTER (ins->sreg1));
197 if (cfg->verbose_level > 2) { printf ("Found candidate load:"); mono_print_ins (ins); }
198 needs_dce |= lower_load (cfg, ins, tmp);
202 case OP_STORE_MEMBASE_REG:
203 case OP_STOREI1_MEMBASE_REG:
204 case OP_STOREI2_MEMBASE_REG:
205 case OP_STOREI4_MEMBASE_REG:
206 case OP_STOREI8_MEMBASE_REG:
207 case OP_STORER4_MEMBASE_REG:
208 case OP_STORER8_MEMBASE_REG:
209 case OP_STOREV_MEMBASE:
210 if (ins->inst_offset != 0)
212 tmp = g_hash_table_lookup (addr_loads, GINT_TO_POINTER (ins->dreg));
214 if (cfg->verbose_level > 2) { printf ("Found candidate store:"); mono_print_ins (ins); }
215 needs_dce |= lower_store (cfg, ins, tmp);
219 case OP_STORE_MEMBASE_IMM:
220 case OP_STOREI4_MEMBASE_IMM:
221 case OP_STOREI8_MEMBASE_IMM:
222 if (ins->inst_offset != 0)
224 tmp = g_hash_table_lookup (addr_loads, GINT_TO_POINTER (ins->dreg));
226 if (cfg->verbose_level > 2) { printf ("Found candidate store-imm:"); mono_print_ins (ins); }
227 needs_dce |= lower_store_imm (cfg, ins, tmp);
233 g_hash_table_destroy (addr_loads);
238 recompute_aliased_variables (MonoCompile *cfg)
246 for (i = 0; i < cfg->num_varinfo; i++) {
247 MonoInst *var = cfg->varinfo [i];
248 if (var->flags & MONO_INST_INDIRECT) {
249 if (cfg->verbose_level > 2) {
250 printf ("Killing :"); mono_print_ins (var);
254 var->flags &= ~MONO_INST_INDIRECT;
260 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
261 for (ins = bb->code; ins; ins = ins->next) {
262 if (ins->opcode == OP_LDADDR) {
265 if (cfg->verbose_level > 2) { printf ("Found op :"); mono_print_ins (ins); }
267 var = (MonoInst*)ins->inst_p0;
268 if (!(var->flags & MONO_INST_INDIRECT)) {
269 if (cfg->verbose_level) { printf ("Restoring :"); mono_print_ins (var); }
272 var->flags |= MONO_INST_INDIRECT;
277 mono_jit_stats.alias_found += kills;
278 mono_jit_stats.alias_removed += kills - adds;
280 if (cfg->verbose_level > 2) {
281 printf ("Method: %s\n", mono_method_full_name (cfg->method, 1));
282 printf ("Kills %d Adds %d\n", kills, adds);
291 Don't DCE on the whole CFG, only the BBs that have changed.
294 SRVT of small types can fix cases of mismatch for fields of a different type than the component.
295 Handle aliasing of byrefs in call conventions.
298 mono_local_alias_analysis (MonoCompile *cfg)
300 if (!cfg->has_indirection)
303 if (cfg->verbose_level > 2)
304 mono_print_code (cfg, "BEFORE ALIAS_ANALYSIS");
307 Remove indirection and memory access of known variables.
309 if (!lower_memory_access (cfg))
313 By replacing indirect access with direct operations, some LDADDR ops become dead. Kill them.
315 if (cfg->opt & MONO_OPT_DEADCE)
316 mono_local_deadce (cfg);
319 Some variables no longer need to be flagged as indirect, find them.
321 if (!recompute_aliased_variables (cfg))
325 A lot of simplification just took place, we recompute local variables and do DCE to
326 really profit from the previous gains
328 mono_handle_global_vregs (cfg);
329 if (cfg->opt & MONO_OPT_DEADCE)
330 mono_local_deadce (cfg);
333 if (cfg->verbose_level > 2)
334 mono_print_code (cfg, "AFTER ALIAS_ANALYSIS");