merge -r 60439:60440
[mono.git] / mono / mini / aliasing.c
1 /*
2  * aliasing.c: Alias Analysis
3  *
4  * Author:
5  *   Massimiliano Mantione (massi@ximian.com)
6  *
7  * (C) 2005 Novell, Inc.  http://www.novell.com
8  */
9 #include <string.h>
10 #include <stdio.h>
11
12 #include <mono/metadata/debug-helpers.h>
13 #include <mono/metadata/mempool.h>
14 #include <mono/metadata/opcodes.h>
15
16 #include "aliasing.h"
17
18 #define MONO_APPLY_DEADCE_TO_SINGLE_METHOD 0
19 #define DEBUG_DEADCE 0
20
21 #define DEBUG_ALIAS_ANALYSIS 0
22
23 #define TRACE_ALIAS_ANALYSIS (info->cfg->verbose_level > 2)
24 #define DUMP_ALIAS_ANALYSIS (info->cfg->verbose_level > 4)
25 #define FOLLOW_ALIAS_ANALYSIS (info->cfg->verbose_level > 5)
26
27 static const char *mono_aliasing_value_names[] = {
28         "ANY",
29         "NO_ALIAS",
30         "LOCAL",
31         "LOCAL_FIELD"
32 };
33
34
35 static const char *mono_stack_type_names[] = {
36         "STACK_INV",
37         "STACK_I4",
38         "STACK_I8",
39         "STACK_PTR",
40         "STACK_R8",
41         "STACK_MP",
42         "STACK_OBJ",
43         "STACK_VTYPE",
44         "STACK_MAX"
45 };
46
47 #define NO_VARIABLE_INDEX MONO_ALIASING_INVALID_VARIABLE_INDEX
48
49
50 #define OP_IS_OUTARG(op) (((op)==OP_OUTARG)||((op)==OP_OUTARG_REG)||((op)==OP_OUTARG_IMM)||((op)==OP_OUTARG_R4)||((op)==OP_OUTARG_R8)||((op)==OP_OUTARG_VT))
51 #define OP_IS_CALL(op) (((op)==CEE_CALLI)||((op)==CEE_CALL)||((op)==CEE_CALLVIRT)||(((op)>=OP_VOIDCALL)&&((op)<=OP_CALL_MEMBASE)))
52 #define OP_IS_STORE(op) (((op)==CEE_STIND_REF)||((op)==CEE_STIND_I1)||((op)==CEE_STIND_I2)||((op)==CEE_STIND_I4)||((op)==CEE_STIND_I8)||((op)==CEE_STIND_R4)||((op)==CEE_STIND_R8)||((op)==CEE_STIND_I))
53 #define OP_IS_LOAD(op) (((op)==CEE_LDIND_REF)||((op)==CEE_LDIND_I1)||((op)==CEE_LDIND_I2)||((op)==CEE_LDIND_I4)||((op)==CEE_LDIND_U1)||((op)==CEE_LDIND_U2)||((op)==CEE_LDIND_U4)||((op)==CEE_LDIND_I8)||((op)==CEE_LDIND_R4)||((op)==CEE_LDIND_R8)||((op)==CEE_LDIND_I))
54 #define OP_IS_CONST(op) (((op)==OP_ICONST)||((op)==OP_I8CONST)||((op)==OP_R4CONST)||((op)==OP_R8CONST)||((op)==OP_AOTCONST))
55 #define OP_IS_ICONV(op) (((op)==CEE_CONV_I4)||((op)==CEE_CONV_U4)||((op)==CEE_CONV_I8)||((op)==CEE_CONV_U8)||\
56                 ((op)==CEE_CONV_OVF_I4_UN)||((op)==CEE_CONV_OVF_I8_UN)||((op)==CEE_CONV_OVF_U4_UN)||((op)==CEE_CONV_OVF_U8_UN)||\
57                 ((op)==CEE_CONV_OVF_I4)||((op)==CEE_CONV_OVF_U4)||((op)==CEE_CONV_OVF_I8)||((op)==CEE_CONV_OVF_U8))
58 #define OP_IS_PCONV(op) (((op)==CEE_CONV_OVF_I_UN)||((op)==CEE_CONV_OVF_U_UN)||\
59                 ((op)==CEE_CONV_I)||((op)==CEE_CONV_U)||\
60                 ((op)==CEE_CONV_OVF_I)||((op)==CEE_CONV_OVF_U))
61 #define LOAD_OF_LOCAL_GIVES_POINTER(load,local) ((local->opcode == OP_LOCAL) && (((load)->type == STACK_MP) || ((load)->type == STACK_PTR) || ((local)->inst_vtype->type == MONO_TYPE_PTR)))
62
63
64 /*
65  * A struct representing the context of the traversal of a MonoInst tree.
66  * Used so that "update_aliasing_information_on_inst" can understand what
67  * its caller was doing, and expecially where the current value is going
68  * to be stored (if it is an alias, we must track it).
69  */
70 typedef struct MonoAliasingInformationContext {
71         MonoInst *inst;
72         int current_subtree;
73         MonoAliasValue subtree_aliases [2];
74         
75         struct MonoAliasingInformationContext *father;
76 } MonoAliasingInformationContext;
77
78
79 static void
80 print_alias_value (MonoAliasValue *alias_value) {
81         printf ("[%s", mono_aliasing_value_names [alias_value->type]);
82         if ((alias_value->type == MONO_ALIASING_TYPE_LOCAL) || (alias_value->type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
83                 printf (":%d]", alias_value->variable_index);
84         } else {
85                 printf ("]");
86         }
87 }
88
89 static void
90 print_ssaop_value (int ssaop_value) {
91         printf ("[");
92         if (ssaop_value & MONO_SSA_ADDRESS_TAKEN) printf ("I"); else printf (".");
93         if (ssaop_value & MONO_SSA_LOAD) printf ("R"); else printf (".");
94         if (ssaop_value & MONO_SSA_STORE) printf ("W"); else printf (".");
95         printf ("]");
96 }
97
98 static void
99 print_aliasing_context (MonoAliasingInformationContext *context) {
100         printf ("CONTEXT: left ");
101         print_alias_value (&(context->subtree_aliases [0]));
102         printf (", right ");
103         print_alias_value (&(context->subtree_aliases [1]));
104         if (context->father != NULL) {
105                 printf (", father ");
106                 print_alias_value (&(context->father->subtree_aliases [context->father->current_subtree]));
107         }
108         printf (", stack %s ", mono_stack_type_names [context->inst->type]);
109         if (context->inst->ssa_op != MONO_SSA_NOP) {
110                 print_ssaop_value (context->inst->ssa_op);
111                 printf (" ");
112         }
113         printf ("in inst ");
114         mono_print_tree_nl (context->inst);
115 }
116
117 static void
118 print_tree_node (MonoInst *tree) {
119         if (!tree)
120                 return;
121         
122         printf (mono_inst_name (tree->opcode));
123         
124         if (OP_IS_OUTARG (tree->opcode)) {
125                 printf ("[OUT:%ld]", (long)tree->inst_c1);
126         }
127         
128         switch (tree->opcode) {
129         case OP_ICONST:
130                 printf ("[%d]", (int)tree->inst_c0);
131                 break;
132         case OP_I8CONST:
133                 printf ("[%lld]", (long long)tree->inst_l);
134                 break;
135         case OP_R8CONST:
136                 printf ("[%f]", *(double*)tree->inst_p0);
137                 break;
138         case OP_R4CONST:
139                 printf ("[%f]", *(float*)tree->inst_p0);
140                 break;
141         case OP_ARG:
142         case OP_LOCAL:
143                 printf ("[%d]", (int)tree->inst_c0);
144                 break;
145         case OP_REGOFFSET:
146                 if (tree->inst_offset < 0)
147                         printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
148                 else
149                         printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
150                 break;
151         case OP_REGVAR:
152                 printf ("[%s]", mono_arch_regname (tree->dreg));
153                 break;
154         case CEE_NEWARR:
155                 printf ("[%s]",  tree->inst_newa_class->name);
156                 break;
157         case CEE_CALL:
158         case CEE_CALLVIRT:
159         case OP_FCALL:
160         case OP_FCALLVIRT:
161         case OP_LCALL:
162         case OP_LCALLVIRT:
163         case OP_VCALL:
164         case OP_VCALLVIRT:
165         case OP_VOIDCALL:
166         case OP_VOIDCALLVIRT: {
167                 MonoCallInst *call = (MonoCallInst*)tree;
168                 if (call->method)
169                         printf ("[%s]", call->method->name);
170                 else if (call->fptr) {
171                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
172                         if (info)
173                                 printf ("[%s]", info->name);
174                 }
175                 printf ("[ARGS:%d]", call->signature->param_count);
176                 break;
177         }
178         case OP_PHI: {
179                 int i;
180                 printf ("[%d (", (int)tree->inst_c0);
181                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
182                         if (i)
183                                 printf (", ");
184                         printf ("%d", tree->inst_phi_args [i + 1]);
185                 }
186                 printf (")]");
187                 break;
188         }
189         case OP_LOAD_MEMBASE:
190         case OP_LOADI4_MEMBASE:
191         case OP_LOADU4_MEMBASE:
192         case OP_LOADU1_MEMBASE:
193         case OP_LOADI1_MEMBASE:
194         case OP_LOADU2_MEMBASE:
195         case OP_LOADI2_MEMBASE:
196                 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
197                 break;
198         case CEE_BR:
199         case OP_CALL_HANDLER:
200                 printf ("[B%d]", tree->inst_target_bb->block_num);
201                 break;
202         case CEE_BNE_UN:
203         case CEE_BEQ:
204         case CEE_BLT:
205         case CEE_BLT_UN:
206         case CEE_BGT:
207         case CEE_BGT_UN:
208         case CEE_BGE:
209         case CEE_BGE_UN:
210         case CEE_BLE:
211         case CEE_BLE_UN:
212                 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
213                 break;
214         case OP_DUMMY_USE:
215                 printf ("[%d]", (int)tree->inst_i0->inst_i0->inst_c0);
216                 break;
217         case OP_DUMMY_STORE:
218                 printf ("[%d]", (int)tree->inst_i0->inst_c0);
219                 break;
220         default:
221                 break;
222         }
223 }
224
225 static void
226 print_variable_list (MonoLocalVariableList* variables) {
227         printf ("{");
228         while (variables != NULL) {
229                 printf ("%d", variables->variable_index);
230                 if (variables->next != NULL) {
231                         printf (",");
232                 }
233                 variables = variables->next;
234         }
235         printf ("}");
236 }
237
238 static void
239 print_used_aliases(MonoInst *inst, MonoLocalVariableList* affected_variables) {
240         if (inst->ssa_op != MONO_SSA_NOP) {
241                 printf (" <");
242                 if (inst->ssa_op & MONO_SSA_ADDRESS_TAKEN) printf ("I");
243                 if (inst->ssa_op & MONO_SSA_LOAD) printf ("R");
244                 if (inst->ssa_op & MONO_SSA_STORE) printf ("W");
245                 if (inst->ssa_op != MONO_SSA_ADDRESS_TAKEN) {
246                         print_variable_list (affected_variables);
247                 } else {
248                         switch (inst->inst_i0->opcode) {
249                         case OP_LOCAL:
250                         case OP_ARG:
251                                 printf ("{%ld}", (long)inst->inst_i0->inst_c0);
252                                 break;
253                         case OP_RETARG:
254                                 printf ("{RETARG}");
255                                 break;
256                         default:
257                                 printf ("{ANY}");
258                                 break;
259                         }
260                 }
261                 printf (">");
262         }
263 }
264
265 static void
266 print_tree_with_aliasing_information (MonoAliasingInformation *info, MonoInst *tree) {
267         int arity;
268         MonoLocalVariableList* affected_variables;
269
270         if (!tree) {
271                 printf ("NULL-INST");
272                 return;
273         }
274         
275         arity = mono_burg_arity [tree->opcode];
276         
277         print_tree_node (tree);
278         
279         if (OP_IS_CALL (tree->opcode) && arity) {
280                 printf (" THIS:");
281         }
282         
283         if (arity) {
284                 printf (" (");
285                 print_tree_with_aliasing_information (info, tree->inst_i0);
286                 if (arity > 1) {
287                         printf (" ");
288                         print_tree_with_aliasing_information (info, tree->inst_i1);
289                 }
290                 printf (")");
291         }
292         
293         affected_variables = mono_aliasing_get_affected_variables_for_inst_traversing_code (info, tree);
294         print_used_aliases (tree, affected_variables);
295 }
296
297 static void
298 print_code_with_aliasing_information (MonoAliasingInformation *info) {
299         char *name = mono_method_full_name (info->cfg->method, TRUE);
300         int i;
301         
302         printf ("ALIASING DATA START (METHOD %s)\n", name);
303         printf ("ALIASED VARIABLES: ");
304         print_variable_list (info->uncontrollably_aliased_variables);
305         printf ("\n");
306         for (i = 0; i < info->cfg->num_bblocks; i++) {
307                 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
308                 MonoAliasUsageInformation *use;
309                 MonoInst *inst;
310                 
311                 printf ("CODE FOR BB %d\n", bb_info->bb->block_num);
312                 mono_aliasing_initialize_code_traversal (info, bb_info->bb);
313                 for (inst = bb_info->bb->code; inst != NULL; inst = inst->next) {
314                         print_tree_with_aliasing_information (info, inst);
315                         printf ("\n");
316                 }
317                 
318                 printf ("USES FOR BB %d\n", bb_info->bb->block_num);
319                 for (use = bb_info->potential_alias_uses; use != NULL; use = use->next) {
320                         mono_print_tree (use->inst);
321                         print_used_aliases (use->inst, use->affected_variables);
322                         printf ("\n");
323                 }               
324         }
325         printf ("ALIASING DATA END (METHOD %s)\n", name);
326         g_free (name);
327 }       
328
329
330 #define APPEND_USE(info,bb_info,use) do {\
331                 (use)->next = NULL;\
332                 if ((info)->next_interesting_inst != NULL) {\
333                         (info)->next_interesting_inst->next = (use);\
334                 } else {\
335                         (bb_info)->potential_alias_uses = (use);\
336                 }\
337                 (info)->next_interesting_inst = (use);\
338         } while (0)
339         
340 #define ADD_BAD_ALIAS(info,vi) do {\
341                 if (FOLLOW_ALIAS_ANALYSIS) {\
342                         printf ("ADDING BAD ALIAS FOR VARIABLE %d\n", vi);\
343                 }\
344                 if (! ((info)->variable_is_uncontrollably_aliased [(vi)])) {\
345                         MonoLocalVariableList *variable = mono_mempool_alloc ((info)->mempool, sizeof (MonoLocalVariableList));\
346                         variable->variable_index = (vi);\
347                         variable->next = (info)->uncontrollably_aliased_variables;\
348                         (info)->uncontrollably_aliased_variables = variable;\
349                         (info)->variable_is_uncontrollably_aliased [(vi)] = TRUE;\
350                 }\
351         } while (0)
352
353 #define ADD_ARGUMGENT(info,inst,alias) do {\
354                 if ((info)->number_of_arguments == (info)->arguments_capacity) {\
355                         MonoInst **new_arguments = mono_mempool_alloc ((info)->mempool, sizeof (MonoInst*) * ((info)->arguments_capacity * 2));\
356                         MonoAliasValue *new_arguments_aliases = mono_mempool_alloc ((info)->mempool, sizeof (MonoAliasValue) * ((info)->arguments_capacity * 2));\
357                         memcpy (new_arguments, (info)->arguments, sizeof (MonoInst*) * ((info)->arguments_capacity));\
358                         memcpy (new_arguments_aliases, (info)->arguments_aliases, sizeof (MonoAliasValue) * ((info)->arguments_capacity));\
359                         (info)->arguments = new_arguments;\
360                         (info)->arguments_aliases = new_arguments_aliases;\
361                         (info)->arguments_capacity = (info)->arguments_capacity * 2;\
362                 }\
363                 (info)->arguments [(info)->number_of_arguments] = (inst);\
364                 (info)->arguments_aliases [(info)->number_of_arguments] = (alias);\
365                 (info)->number_of_arguments ++;\
366         } while (0)
367
368 #define ADD_UNIQUE_VARIABLE(info,list,vi) do {\
369                 MonoLocalVariableList* target_element = (list);\
370                 while ((target_element != NULL) && (target_element->variable_index != (vi))) {\
371                         target_element = target_element->next;\
372                 }\
373                 if (target_element == NULL) {\
374                         target_element = mono_mempool_alloc ((info)->mempool, sizeof (MonoLocalVariableList));\
375                         target_element->variable_index = (vi);\
376                         target_element->next = (list);\
377                         (list) = target_element;\
378                 }\
379         } while (0)
380
381 static void
382 update_aliasing_information_on_inst (MonoAliasingInformation *info, MonoAliasingInformationInBB *bb_info, MonoInst *inst, MonoAliasingInformationContext *father_context) {
383         MonoAliasingInformationContext context;
384         MonoAliasValue *father_alias;
385         
386         context.inst = inst;
387         context.father = father_context;
388         if (father_context != NULL) {
389                 father_alias = &(father_context->subtree_aliases [father_context->current_subtree]);
390         } else {
391                 father_alias = NULL;
392         }
393         
394         if (mono_burg_arity [inst->opcode]) {
395                 context.current_subtree = 0;
396                 context.subtree_aliases [0].type = MONO_ALIASING_TYPE_ANY;
397                 context.subtree_aliases [0].variable_index = NO_VARIABLE_INDEX;
398                 update_aliasing_information_on_inst (info, bb_info, inst->inst_i0, &context);
399                 
400                 if (mono_burg_arity [inst->opcode] > 1) {
401                         context.current_subtree = 1;
402                         context.subtree_aliases [1].type = MONO_ALIASING_TYPE_ANY;
403                         context.subtree_aliases [1].variable_index = NO_VARIABLE_INDEX;
404                         update_aliasing_information_on_inst (info, bb_info, inst->inst_i1, &context);
405                 } else {
406                         context.subtree_aliases [1].type = MONO_ALIASING_TYPE_NO_ALIAS;
407                 }
408         } else {
409                 context.subtree_aliases [0].type = MONO_ALIASING_TYPE_NO_ALIAS;
410                 context.subtree_aliases [1].type = MONO_ALIASING_TYPE_NO_ALIAS;
411         }
412         
413         if (OP_IS_CONST (inst->opcode)) {
414                 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
415         } else if (inst->ssa_op == MONO_SSA_ADDRESS_TAKEN) {
416                 MonoInst *local = inst->inst_i0;
417                 if ((local->opcode == OP_LOCAL) || (local->opcode == OP_ARG)) {
418                         gssize variable_index = local->inst_c0;
419                         father_alias->type = MONO_ALIASING_TYPE_LOCAL;
420                         father_alias->variable_index = variable_index;
421                 } else if (local->opcode == OP_RETARG) {
422                         father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
423                 } else {
424                         father_alias->type = MONO_ALIASING_TYPE_ANY;
425                 }
426         } else if (inst->ssa_op == MONO_SSA_LOAD) {
427                 MonoInst *local = inst->inst_i0;
428                 
429                 if (LOAD_OF_LOCAL_GIVES_POINTER (inst,local)) {
430                         father_alias->type = MONO_ALIASING_TYPE_ANY;
431                 } else {
432                         father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
433                 }
434         } else if (OP_IS_LOAD (inst->opcode) || (inst->opcode == CEE_LDOBJ)) {
435                 MonoInst *address = inst->inst_i0;
436                 MonoLocalVariableList *affected_variables = NULL;
437                 
438                 if ((address->opcode == OP_LOCAL) || (address->opcode == OP_ARG)) {
439                         gssize variable_index = address->inst_c0;
440                         MonoInst *local = info->cfg->varinfo [variable_index];
441                         
442                         affected_variables = &(info->variables [variable_index]);
443                         if (LOAD_OF_LOCAL_GIVES_POINTER (inst,local)) {
444                                 father_alias->type = MONO_ALIASING_TYPE_ANY;
445                         } else {
446                                 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
447                         }
448                 } else if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL) {
449                         gssize variable_index = context.subtree_aliases [0].variable_index;
450                         MonoInst *local = info->cfg->varinfo [variable_index];
451                         
452                         affected_variables = &(info->variables [variable_index]);;
453                         if (LOAD_OF_LOCAL_GIVES_POINTER (inst,local)) {
454                                 father_alias->type = MONO_ALIASING_TYPE_ANY;
455                         } else {
456                                 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
457                         }
458                 } else if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD) {
459                         gssize variable_index = context.subtree_aliases [0].variable_index;
460                         
461                         affected_variables = &(info->variables [variable_index]);;
462                         if (inst->type == STACK_MP) {
463                                 father_alias->type = MONO_ALIASING_TYPE_ANY;
464                         } else {
465                                 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
466                         }
467                 } else {
468                         if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) {
469                                 affected_variables = info->temporary_uncontrollably_aliased_variables;
470                         }
471                         if ((inst->type == STACK_MP) && (inst->inst_i0->opcode != OP_OBJADDR)) {
472                                 father_alias->type = MONO_ALIASING_TYPE_ANY;
473                         } else {
474                                 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
475                         }
476                 }
477                 
478                 if (affected_variables != NULL) {
479                         MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
480                         
481                         inst->ssa_op = MONO_SSA_INDIRECT_LOAD;
482                         use->inst = inst;
483                         use->affected_variables = affected_variables;
484                         APPEND_USE (info,bb_info,use);
485                 }
486         } else if (inst->ssa_op == MONO_SSA_STORE) {
487                 if (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL) {
488                         ADD_BAD_ALIAS (info, context.subtree_aliases [1].variable_index);
489                 }
490         } else if (OP_IS_STORE (inst->opcode) || (inst->opcode == CEE_STOBJ)) {
491                 MonoInst *address = inst->inst_i0;
492                 MonoLocalVariableList *affected_variables = NULL;
493                 
494                 if (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL) {
495                         ADD_BAD_ALIAS (info, context.subtree_aliases [1].variable_index);
496                 }
497                 
498                 if ((address->opcode == OP_LOCAL) || (address->opcode == OP_ARG)) {
499                         gssize variable_index = address->inst_c0;
500                         
501                         affected_variables = &(info->variables [variable_index]);
502                 } else if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
503                         gssize variable_index = context.subtree_aliases [0].variable_index;
504                         
505                         affected_variables = &(info->variables [variable_index]);;
506                 } else if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) {
507                         affected_variables = info->temporary_uncontrollably_aliased_variables;
508                 }
509                 
510                 if (affected_variables != NULL) {
511                         MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
512                         
513                         inst->ssa_op = MONO_SSA_INDIRECT_STORE;
514                         use->inst = inst;
515                         use->affected_variables = affected_variables;
516                         APPEND_USE (info,bb_info,use);
517                 }
518         } else if (OP_IS_OUTARG (inst->opcode)) {
519                 ADD_ARGUMGENT (info,inst,context.subtree_aliases [0]);
520         } else if (OP_IS_CALL (inst->opcode)) {
521                 MonoCallInst *call = (MonoCallInst *) inst;
522                 MonoMethodSignature *sig = call->signature;
523                 gboolean call_has_untracked_pointer_argument = FALSE;
524                 MonoLocalVariableList *alias_arguments = NULL;
525                 int i;
526                 
527                 if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
528                         ADD_UNIQUE_VARIABLE (info,alias_arguments,context.subtree_aliases [0].variable_index);
529                 } else if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) {
530                         call_has_untracked_pointer_argument = TRUE;
531                 }
532                 
533                 if (FOLLOW_ALIAS_ANALYSIS) {
534                         printf ("CALL, scanning %d arguments\n", info->number_of_arguments);
535                 }
536                 for (i = 0; i < info->number_of_arguments; i++) {
537                         //FIXME
538                         //MonoInst *argument = info->arguments [i];
539                         MonoAliasValue arguments_alias = info->arguments_aliases [i];
540                         
541                         if ((arguments_alias.type == MONO_ALIASING_TYPE_LOCAL) || (arguments_alias.type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
542                                 if (FOLLOW_ALIAS_ANALYSIS) {
543                                         printf ("CALL, argument %d passes the address of local %d\n", i, arguments_alias.variable_index);
544                                 }
545                                 ADD_UNIQUE_VARIABLE (info,alias_arguments,arguments_alias.variable_index);
546                                 //FIXME
547                                 #if 0
548                                 if (((arguments_alias.type == MONO_ALIASING_TYPE_LOCAL)) && (argument->inst_c1 > 0)) {
549                                         int argument_index = argument->inst_c1 - 1;
550                                         if (argument_index < sig->param_count) {
551                                                 if (! (sig->params [argument_index]->byref)) {
552                                                         ADD_BAD_ALIAS (info, arguments_alias.variable_index);
553                                                 }
554                                         } else {
555                                                 printf ("*** ERROR: argument %d of %d: ", argument_index, sig->param_count);
556                                                 mono_print_tree_nl (argument);
557                                         }
558                                 }
559                                 #endif
560                         } else if (arguments_alias.type == MONO_ALIASING_TYPE_ANY) {
561                                 if (FOLLOW_ALIAS_ANALYSIS) {
562                                         printf ("CALL, argument %d could pass the address of any local\n", i);
563                                 }
564                                 call_has_untracked_pointer_argument = TRUE;
565                         }
566                         //FIXME
567                         #if 0
568                         else if (argument->inst_c1 > 0) {
569                                 int argument_index = argument->inst_c1 - 1;
570                                 if (argument_index < sig->param_count) {
571                                         if (sig->params [argument_index]->type == MONO_TYPE_PTR) {
572                                                 call_has_untracked_pointer_argument = TRUE;
573                                         }
574                                 } else {
575                                         printf ("*** ERROR: argument %d of %d: ", argument_index, sig->param_count);
576                                         mono_print_tree_nl (argument);
577                                 }
578                         }
579                         #endif
580                 }
581                 
582                 if ((alias_arguments != NULL) || call_has_untracked_pointer_argument) {
583                         MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
584                         
585                         inst->ssa_op = MONO_SSA_INDIRECT_LOAD_STORE;
586                         use->inst = inst;
587                         use->affected_variables = alias_arguments;
588                         if (call_has_untracked_pointer_argument) {
589                                 MonoLocalVariableList *untracked_element  = mono_mempool_alloc ((info)->mempool, sizeof (MonoLocalVariableList));
590                                 untracked_element->variable_index = NO_VARIABLE_INDEX;
591                                 untracked_element->next = use->affected_variables;
592                                 use->affected_variables = untracked_element;
593                         }
594                         APPEND_USE (info,bb_info,use);
595                 }
596                 
597                 if ((sig->ret != NULL) && (father_alias != NULL)) {
598                         if (sig->ret->type != MONO_TYPE_PTR) {
599                                 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
600                         } else {
601                                 father_alias->type = MONO_ALIASING_TYPE_ANY;
602                         }
603                 }
604                 
605                 info->number_of_arguments = 0;
606         } else if ((inst->opcode == CEE_ADD) || (inst->opcode == OP_LADD)){
607                 if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
608                         int variable_index = context.subtree_aliases [0].variable_index;
609                         //ADD_BAD_ALIAS (info, variable_index);
610                         father_alias->type = MONO_ALIASING_TYPE_LOCAL_FIELD;
611                         father_alias->variable_index = variable_index;
612                 } else if ((context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
613                         int variable_index = context.subtree_aliases [1].variable_index;
614                         //ADD_BAD_ALIAS (info, variable_index);
615                         father_alias->type = MONO_ALIASING_TYPE_LOCAL_FIELD;
616                         father_alias->variable_index = variable_index;
617                 } else if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) || (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_ANY)) {
618                         father_alias->type = MONO_ALIASING_TYPE_ANY;
619                 } else {
620                         father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
621                 }
622         } else if ((inst->opcode == OP_MEMCPY) || (inst->opcode == OP_MEMSET)) {
623                 if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
624                         MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
625                         
626                         inst->ssa_op = MONO_SSA_INDIRECT_STORE;
627                         use->inst = inst;
628                         use->affected_variables = &(info->variables [context.subtree_aliases [0].variable_index]);
629                         APPEND_USE (info,bb_info,use);
630                 } else if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) {
631                         MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
632                         
633                         inst->ssa_op = MONO_SSA_INDIRECT_STORE;
634                         use->inst = inst;
635                         use->affected_variables = info->temporary_uncontrollably_aliased_variables;
636                         APPEND_USE (info,bb_info,use);
637                 }
638         } else if ((inst->opcode == OP_UNBOXCAST) || OP_IS_PCONV (inst->opcode) || OP_IS_ICONV (inst->opcode)) {
639                 father_alias->type = context.subtree_aliases [0].type;
640                 father_alias->variable_index = context.subtree_aliases [0].variable_index;
641         } else if ((inst->opcode == CEE_LDELEMA) || (inst->opcode == OP_COMPARE) || (inst->opcode == CEE_SWITCH)) {
642                 if (father_alias != NULL) {
643                         father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
644                 }
645         } else {
646                 MonoAliasType father_type = MONO_ALIASING_TYPE_NO_ALIAS;
647                 if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
648                         ADD_BAD_ALIAS (info, context.subtree_aliases [0].variable_index);
649                 }
650                 if ((context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
651                         ADD_BAD_ALIAS (info, context.subtree_aliases [1].variable_index);
652                 }
653                 if (father_alias != NULL) { 
654                         if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) || (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_ANY)) {
655                                 father_type = MONO_ALIASING_TYPE_ANY;
656                         }
657                         father_alias->type = father_type;
658                 }
659         }
660         
661         if (FOLLOW_ALIAS_ANALYSIS) {
662                 print_aliasing_context (&context);
663         }
664 }
665
666
667
668 /**
669  * mono_build_aliasing_information:
670  * @cfg: Control Flow Graph
671  *
672  * Builds the aliasing information in a cfg.
673  * After this has run, all MonoInst.ssa_op fields will be properly
674  * set (it will use the MONO_SSA_ADDRESS_TAKEN, MONO_SSA_LOAD and
675  * MONO_SSA_STORE values as a starting point).
676  */
677 MonoAliasingInformation*
678 mono_build_aliasing_information (MonoCompile *cfg) {
679         MonoMemPool *pool = mono_mempool_new ();
680         MonoAliasingInformation *info = mono_mempool_alloc (pool, sizeof (MonoAliasingInformation));
681         int i;
682 #if (DEBUG_ALIAS_ANALYSIS)
683         int verbose_level = cfg->verbose_level;
684         cfg->verbose_level = 7;
685 #endif
686         
687         info->mempool = pool;
688         info->cfg = cfg;
689         info->bb = mono_mempool_alloc (pool, sizeof (MonoAliasingInformationInBB) * cfg->num_bblocks);
690         info->uncontrollably_aliased_variables = NULL;
691         info->next_interesting_inst = NULL;
692         info->variables = mono_mempool_alloc (pool, sizeof (MonoLocalVariableList) * cfg->num_varinfo);
693         info->variable_is_uncontrollably_aliased = mono_mempool_alloc (pool, sizeof (gboolean) * cfg->num_varinfo);
694         for (i = 0; i < cfg->num_varinfo; i++) {
695                 info->variables [i].next = NULL;
696                 info->variables [i].variable_index = i;
697                 info->variable_is_uncontrollably_aliased [i] = FALSE;
698         }
699         info->temporary_uncontrollably_aliased_variables = mono_mempool_alloc (pool, sizeof (MonoLocalVariableList));
700         info->temporary_uncontrollably_aliased_variables->next = NULL;
701         info->temporary_uncontrollably_aliased_variables->variable_index = NO_VARIABLE_INDEX;
702         info->arguments = mono_mempool_alloc (pool, sizeof (MonoInst*) * 16);
703         info->arguments_aliases = mono_mempool_alloc (pool, sizeof (MonoAliasValue) * 16);
704         info->arguments_capacity = 16;
705         info->number_of_arguments = 0;
706         
707         for (i = 0; i < cfg->num_bblocks; i++) {
708                 MonoBasicBlock *bb = cfg->bblocks [i];
709                 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
710                 MonoInst *inst;
711                 
712                 if (FOLLOW_ALIAS_ANALYSIS) {
713                         printf ("TRAVERSING BB %d\n", bb->block_num);
714                 }
715                 
716                 bb_info->bb = bb;
717                 bb_info->potential_alias_uses = NULL;
718                 info->next_interesting_inst = NULL;
719                 
720                 for (inst = bb->code; inst != NULL; inst = inst->next) {
721                         if (FOLLOW_ALIAS_ANALYSIS) {
722                                 printf ("TRAVERSING INST: ");
723                                 mono_print_tree_nl (inst);
724                         }
725                         update_aliasing_information_on_inst (info, bb_info, inst, NULL);
726                 }
727                 
728                 g_assert (info->number_of_arguments == 0);
729         }
730         
731         //FIXME
732         //#if 0
733         for (i = 0; i < cfg->num_bblocks; i++) {
734                 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
735                 MonoAliasUsageInformation *use;
736                 
737                 for (use = bb_info->potential_alias_uses; use != NULL; use = use->next) {
738                         if ((use->affected_variables != NULL) && (use->affected_variables->variable_index == NO_VARIABLE_INDEX)) {
739                                 if (use->affected_variables->next == NULL) {
740                                         use->affected_variables = info->uncontrollably_aliased_variables;
741                                 } else {
742                                         MonoLocalVariableList *last = use->affected_variables;
743                                         while (last->next != NULL) {
744                                                 while (last->next && info->variable_is_uncontrollably_aliased [last->next->variable_index]) {
745                                                         last->next = last->next->next;
746                                                 }
747                                                 if (last->next != NULL) {
748                                                         last = last->next;
749                                                 }
750                                         }
751                                         if (last->variable_index != NO_VARIABLE_INDEX) {
752                                                 use->affected_variables = use->affected_variables->next;
753                                                 last->next = info->uncontrollably_aliased_variables;
754                                         } else {
755                                                 use->affected_variables = info->uncontrollably_aliased_variables;
756                                         }
757                                 }
758                         }
759                 }
760         }
761         //#endif
762         
763         if (DUMP_ALIAS_ANALYSIS) {
764                 print_code_with_aliasing_information (info);
765         }
766         
767 #if (DEBUG_ALIAS_ANALYSIS)
768         cfg->verbose_level = verbose_level;
769 #endif
770         
771         return info;
772 }
773
774
775 void
776 mono_destroy_aliasing_information (MonoAliasingInformation *info) {
777         mono_mempool_destroy (info->mempool);
778 }
779
780 void
781 mono_aliasing_initialize_code_traversal (MonoAliasingInformation *info, MonoBasicBlock *bb) {
782         info->next_interesting_inst = info->bb [bb->dfn].potential_alias_uses;
783 }
784
785 MonoLocalVariableList*
786 mono_aliasing_get_affected_variables_for_inst_traversing_code (MonoAliasingInformation *info, MonoInst *inst) {
787         if ((inst->ssa_op == MONO_SSA_LOAD) || (inst->ssa_op == MONO_SSA_STORE)) {
788                 return &(info->variables [inst->inst_i0->inst_c0]);
789         } else if (info->next_interesting_inst != NULL) {
790                 if (inst == info->next_interesting_inst->inst) {
791                         MonoLocalVariableList *result = info->next_interesting_inst->affected_variables;
792                         info->next_interesting_inst = info->next_interesting_inst->next;
793                         return result;
794                 } else if (inst->ssa_op != MONO_SSA_NOP) {
795                         if (inst->ssa_op == MONO_SSA_ADDRESS_TAKEN) {
796                                 return NULL;
797                         } else {
798                                 printf ("ERROR: instruction not found '");
799                                 //print_tree_with_aliasing_information (info, inst);
800                                 mono_print_tree (inst);
801                                 printf ("'\n");
802                                 //g_assert_not_reached ();
803                                 return NULL;
804                         }
805                 } else {
806                         return NULL;
807                 }
808         } else {
809                 return NULL;
810         }
811 }
812
813 static MonoLocalVariableList*
814 mono_aliasing_get_affected_variables_for_inst_in_bb (MonoAliasingInformation *info, MonoInst *inst, MonoBasicBlock *bb) {
815         MonoAliasUsageInformation *use;
816         
817         for (use = info->bb [bb->dfn].potential_alias_uses; use != NULL; use = use->next) {
818                 if (use->inst == inst) {
819                         return use->affected_variables;
820                 }
821         }
822         g_assert_not_reached ();
823         return NULL;
824 }
825
826 MonoLocalVariableList*
827 mono_aliasing_get_affected_variables_for_inst (MonoAliasingInformation *info, MonoInst *inst) {
828         int i;
829         
830         for (i = 0; i < info->cfg->num_bblocks; i++) {
831                 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
832                 MonoAliasUsageInformation *use;
833                 
834                 for (use = info->bb [bb_info->bb->dfn].potential_alias_uses; use != NULL; use = use->next) {
835                         if (use->inst == inst) {
836                                 return use->affected_variables;
837                         }
838                 }
839         }
840         g_assert_not_reached ();
841         return NULL;
842 }
843
844 #if (MONO_APPLY_DEADCE_TO_SINGLE_METHOD)
845 static char*
846 mono_deadce_method_name = NULL;
847 static gboolean check_deadce_method_name (MonoCompile *cfg) {
848         gboolean result;
849         if (mono_deadce_method_name == NULL) {
850                 mono_deadce_method_name = getenv ("MONO_DEADCE_METHOD_NAME");
851         }
852         if (mono_deadce_method_name != NULL) {
853                 char *method_name = mono_method_full_name (cfg->method, TRUE);
854                 if (strstr (method_name, mono_deadce_method_name) != NULL) {
855                         result = TRUE;
856                 } else {
857                         result = FALSE;
858                 }
859                 g_free (method_name);
860         } else {
861                 result = TRUE;
862         }
863         return result;
864 }
865 #endif
866
867
868
869 #if (DEBUG_DEADCE)
870 #define LOG_DEADCE (info->cfg->verbose_level > 0)
871 #else
872 #define LOG_DEADCE (info->cfg->verbose_level > 4)
873 #endif
874
875 static gboolean
876 mono_aliasing_deadce_on_inst (MonoAliasingInformation *info, MonoInst **possibly_dead_assignments, MonoInst *inst) {
877         int arity;
878         gboolean has_side_effects;
879         MonoLocalVariableList *affected_variables;
880         
881         arity = mono_burg_arity [inst->opcode];
882         
883         if (OP_IS_CALL (inst->opcode)) {
884                 has_side_effects = TRUE;
885         } else {
886                 has_side_effects = FALSE;
887         }
888         
889         if (arity) {
890                 if (mono_aliasing_deadce_on_inst (info, possibly_dead_assignments, inst->inst_i0)) {
891                         has_side_effects = TRUE;
892                 }
893                 if (arity > 1) {
894                         if (mono_aliasing_deadce_on_inst (info, possibly_dead_assignments, inst->inst_i1)) {
895                                 has_side_effects = TRUE;
896                         }
897                         
898                 }
899         }
900         
901         affected_variables = mono_aliasing_get_affected_variables_for_inst_traversing_code (info, inst);
902         
903         if (affected_variables != NULL) {
904                 if (inst->ssa_op & MONO_SSA_LOAD) {
905                         MonoLocalVariableList *affected_variable;
906                         for (affected_variable = affected_variables; affected_variable != NULL; affected_variable = affected_variable->next) {
907                                 if (LOG_DEADCE) {
908                                         printf ("CLEARING slot %d at inst ", affected_variable->variable_index);
909                                         mono_print_tree_nl (inst);
910                                 }
911                                 possibly_dead_assignments [affected_variable->variable_index] = NULL;
912                         }
913                 }
914                 if (inst->ssa_op & MONO_SSA_STORE) {
915                         MonoLocalVariableList *affected_variable;
916                         for (affected_variable = affected_variables; affected_variable != NULL; affected_variable = affected_variable->next) {
917                                 if (possibly_dead_assignments [affected_variable->variable_index] != NULL) {
918                                         if (LOG_DEADCE) {
919                                                 printf ("KILLING slot %d at inst ", affected_variable->variable_index);
920                                                 mono_print_tree_nl (inst);
921                                         }
922                                         possibly_dead_assignments [affected_variable->variable_index]->opcode = CEE_NOP;
923                                         possibly_dead_assignments [affected_variable->variable_index]->ssa_op = MONO_SSA_NOP;
924                                         possibly_dead_assignments [affected_variable->variable_index] = NULL;
925                                 }
926                         }
927                         
928                         //printf ("FAST DEADCE TOTAL LOCAL\n");
929                 }
930                 
931         }
932         
933         if ((! has_side_effects) && (inst->ssa_op == MONO_SSA_STORE)) {
934                 if (LOG_DEADCE) {
935                         printf ("FILLING slot %d with inst ", (int)inst->inst_i0->inst_c0);
936                         mono_print_tree_nl (inst);
937                 }
938                 possibly_dead_assignments [inst->inst_i0->inst_c0] = inst;
939         }
940         
941         return has_side_effects;
942 }
943
944
945 void
946 mono_aliasing_deadce (MonoAliasingInformation *info) {
947         MonoCompile *cfg;
948         MonoInst **possibly_dead_assignments;
949         int i;
950                 
951         cfg = info->cfg;
952         
953         possibly_dead_assignments = alloca (cfg->num_varinfo * sizeof (MonoInst*));
954         
955         if (LOG_DEADCE) {
956                 printf ("BEFORE DEADCE START\n");
957                 mono_print_code (cfg);
958                 printf ("BEFORE DEADCE END\n");
959         }
960         
961 #if (MONO_APPLY_DEADCE_TO_SINGLE_METHOD)
962         if (! check_deadce_method_name (cfg)) {
963                 if (LOG_DEADCE) {
964                         printf ("DEADCE disabled setting MONO_DEADCE_METHOD_NAME\n");
965                 }
966                 return;
967         }
968 #endif
969         
970         for (i = 0; i < cfg->num_bblocks; i++) {
971                 MonoBasicBlock *bb;
972                 MonoInst *inst;
973                 int variable_index;
974                 
975                 bb = cfg->bblocks [i];
976                 memset (possibly_dead_assignments, 0, cfg->num_varinfo * sizeof (MonoInst*));
977                 mono_aliasing_initialize_code_traversal (info, bb);
978                 
979                 if (LOG_DEADCE) {
980                         printf ("Working on BB %d\n", bb->block_num);
981                 }
982                 
983                 for (inst = bb->code; inst != NULL; inst = inst->next) {
984                         mono_aliasing_deadce_on_inst (info, possibly_dead_assignments, inst);
985                         if (inst->opcode == CEE_JMP) {
986                                 /* Keep arguments live! */
987                                 for (variable_index = 0; variable_index < cfg->num_varinfo; variable_index++) {
988                                         if (cfg->varinfo [variable_index]->opcode == OP_ARG) {
989                                                 if (LOG_DEADCE) {
990                                                         printf ("FINALLY CLEARING slot %d (JMP), inst was ", variable_index);
991                                                         mono_print_tree_nl (possibly_dead_assignments [variable_index]);
992                                                 }
993                                                 possibly_dead_assignments [variable_index] = NULL;
994                                         }
995                                 }
996                         }
997                 }
998                 
999                 for (variable_index = 0; variable_index < cfg->num_varinfo; variable_index++) {
1000                         if ((possibly_dead_assignments [variable_index] != NULL) && (! mono_bitset_test (bb->live_out_set, variable_index))) {
1001                                 if (LOG_DEADCE) {
1002                                         printf ("FINALLY KILLING slot %d, inst was ", variable_index);
1003                                         mono_print_tree_nl (possibly_dead_assignments [variable_index]);
1004                                 }
1005                                 
1006                                 //printf ("FAST DEADCE DEAD LOCAL\n");
1007                                 
1008                                 possibly_dead_assignments [variable_index]->opcode = CEE_NOP;
1009                                 possibly_dead_assignments [variable_index]->ssa_op = MONO_SSA_NOP;
1010                         }
1011                 }
1012         }
1013         
1014         if (LOG_DEADCE) {
1015                 printf ("AFTER DEADCE START\n");
1016                 mono_print_code (cfg);
1017                 printf ("AFTER DEADCE END\n");
1018         }
1019 }