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