2 * aliasing.c: Alias Analysis
5 * Massimiliano Mantione (massi@ximian.com)
7 * (C) 2005 Novell, Inc. http://www.novell.com
12 #include <mono/metadata/debug-helpers.h>
13 #include <mono/metadata/mempool.h>
14 #include <mono/metadata/opcodes.h>
18 extern guint8 mono_burg_arity [];
20 #define MONO_APPLY_DEADCE_TO_SINGLE_METHOD 0
21 #define DEBUG_DEADCE 0
23 #define DEBUG_ALIAS_ANALYSIS 0
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)
29 static const char *mono_aliasing_value_names[] = {
37 static const char *mono_stack_type_names[] = {
49 #define NO_VARIABLE_INDEX MONO_ALIASING_INVALID_VARIABLE_INDEX
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)))
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).
65 typedef struct MonoAliasingInformationContext {
68 MonoAliasValue subtree_aliases [2];
70 struct MonoAliasingInformationContext *father;
71 } MonoAliasingInformationContext;
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);
85 print_ssaop_value (int ssaop_value) {
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 (".");
94 print_aliasing_context (MonoAliasingInformationContext *context) {
95 printf ("CONTEXT: left ");
96 print_alias_value (&(context->subtree_aliases [0]));
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]));
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);
109 mono_print_tree_nl (context->inst);
113 print_tree_node (MonoInst *tree) {
117 printf (mono_inst_name (tree->opcode));
119 if (OP_IS_OUTARG (tree->opcode)) {
120 printf ("[OUT:%ld]", (long)tree->inst_c1);
123 switch (tree->opcode) {
125 printf ("[%d]", (int)tree->inst_c0);
128 printf ("[%lld]", (long long)tree->inst_l);
131 printf ("[%f]", *(double*)tree->inst_p0);
134 printf ("[%f]", *(float*)tree->inst_p0);
138 printf ("[%d]", (int)tree->inst_c0);
141 if (tree->inst_offset < 0)
142 printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
144 printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
147 printf ("[%s]", mono_arch_regname (tree->dreg));
150 printf ("[%s]", tree->inst_newa_class->name);
161 case OP_VOIDCALLVIRT: {
162 MonoCallInst *call = (MonoCallInst*)tree;
164 printf ("[%s]", call->method->name);
165 else if (call->fptr) {
166 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
168 printf ("[%s]", info->name);
170 printf ("[ARGS:%d]", call->signature->param_count);
175 printf ("[%d (", (int)tree->inst_c0);
176 for (i = 0; i < tree->inst_phi_args [0]; i++) {
179 printf ("%d", tree->inst_phi_args [i + 1]);
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);
194 case OP_CALL_HANDLER:
195 printf ("[B%d]", tree->inst_target_bb->block_num);
207 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
210 printf ("[%d]", (int)tree->inst_i0->inst_i0->inst_c0);
213 printf ("[%d]", (int)tree->inst_i0->inst_c0);
221 print_variable_list (MonoLocalVariableList* variables) {
223 while (variables != NULL) {
224 printf ("%d", variables->variable_index);
225 if (variables->next != NULL) {
228 variables = variables->next;
234 print_used_aliases(MonoInst *inst, MonoLocalVariableList* affected_variables) {
235 if (inst->ssa_op != MONO_SSA_NOP) {
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);
243 switch (inst->inst_i0->opcode) {
246 printf ("{%ld}", (long)inst->inst_i0->inst_c0);
261 print_tree_with_aliasing_information (MonoAliasingInformation *info, MonoInst *tree) {
263 MonoLocalVariableList* affected_variables;
266 printf ("NULL-INST");
270 arity = mono_burg_arity [tree->opcode];
272 print_tree_node (tree);
274 if (OP_IS_CALL (tree->opcode) && arity) {
280 print_tree_with_aliasing_information (info, tree->inst_i0);
283 print_tree_with_aliasing_information (info, tree->inst_i1);
288 affected_variables = mono_aliasing_get_affected_variables_for_inst_traversing_code (info, tree);
289 print_used_aliases (tree, affected_variables);
293 print_code_with_aliasing_information (MonoAliasingInformation *info) {
294 char *name = mono_method_full_name (info->cfg->method, TRUE);
297 printf ("ALIASING DATA START (METHOD %s)\n", name);
298 printf ("ALIASED VARIABLES: ");
299 print_variable_list (info->uncontrollably_aliased_variables);
301 for (i = 0; i < info->cfg->num_bblocks; i++) {
302 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
303 MonoAliasUsageInformation *use;
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);
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);
320 printf ("ALIASING DATA END (METHOD %s)\n", name);
325 #define APPEND_USE(info,bb_info,use) do {\
327 if ((info)->next_interesting_inst != NULL) {\
328 (info)->next_interesting_inst->next = (use);\
330 (bb_info)->potential_alias_uses = (use);\
332 (info)->next_interesting_inst = (use);\
335 #define ADD_BAD_ALIAS(info,vi) do {\
336 if (FOLLOW_ALIAS_ANALYSIS) {\
337 printf ("ADDING BAD ALIAS FOR VARIABLE %d\n", vi);\
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;\
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;\
358 (info)->arguments [(info)->number_of_arguments] = (inst);\
359 (info)->arguments_aliases [(info)->number_of_arguments] = (alias);\
360 (info)->number_of_arguments ++;\
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;\
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;\
377 update_aliasing_information_on_inst (MonoAliasingInformation *info, MonoAliasingInformationInBB *bb_info, MonoInst *inst, MonoAliasingInformationContext *father_context) {
378 MonoAliasingInformationContext context;
379 MonoAliasValue *father_alias;
382 context.father = father_context;
383 if (father_context != NULL) {
384 father_alias = &(father_context->subtree_aliases [father_context->current_subtree]);
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);
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);
401 context.subtree_aliases [1].type = MONO_ALIASING_TYPE_NO_ALIAS;
404 context.subtree_aliases [0].type = MONO_ALIASING_TYPE_NO_ALIAS;
405 context.subtree_aliases [1].type = MONO_ALIASING_TYPE_NO_ALIAS;
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;
419 father_alias->type = MONO_ALIASING_TYPE_ANY;
421 } else if (inst->ssa_op == MONO_SSA_LOAD) {
422 MonoInst *local = inst->inst_i0;
424 if (LOAD_OF_LOCAL_GIVES_POINTER (inst,local)) {
425 father_alias->type = MONO_ALIASING_TYPE_ANY;
427 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
429 } else if (OP_IS_LOAD (inst->opcode) || (inst->opcode == CEE_LDOBJ)) {
430 MonoInst *address = inst->inst_i0;
431 MonoLocalVariableList *affected_variables = NULL;
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];
437 affected_variables = &(info->variables [variable_index]);
438 if (LOAD_OF_LOCAL_GIVES_POINTER (inst,local)) {
439 father_alias->type = MONO_ALIASING_TYPE_ANY;
441 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
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];
447 affected_variables = &(info->variables [variable_index]);;
448 if (LOAD_OF_LOCAL_GIVES_POINTER (inst,local)) {
449 father_alias->type = MONO_ALIASING_TYPE_ANY;
451 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
453 } else if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD) {
454 gssize variable_index = context.subtree_aliases [0].variable_index;
456 affected_variables = &(info->variables [variable_index]);;
457 if (inst->type == STACK_MP) {
458 father_alias->type = MONO_ALIASING_TYPE_ANY;
460 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
463 if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) {
464 affected_variables = info->temporary_uncontrollably_aliased_variables;
466 if ((inst->type == STACK_MP) && (inst->inst_i0->opcode != OP_OBJADDR)) {
467 father_alias->type = MONO_ALIASING_TYPE_ANY;
469 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
473 if (affected_variables != NULL) {
474 MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
476 inst->ssa_op = MONO_SSA_INDIRECT_LOAD;
478 use->affected_variables = affected_variables;
479 APPEND_USE (info,bb_info,use);
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);
485 } else if (OP_IS_STORE (inst->opcode) || (inst->opcode == CEE_STOBJ)) {
486 MonoInst *address = inst->inst_i0;
487 MonoLocalVariableList *affected_variables = NULL;
489 if (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL) {
490 ADD_BAD_ALIAS (info, context.subtree_aliases [1].variable_index);
493 if ((address->opcode == OP_LOCAL) || (address->opcode == OP_ARG)) {
494 gssize variable_index = address->inst_c0;
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;
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;
505 if (affected_variables != NULL) {
506 MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
508 inst->ssa_op = MONO_SSA_INDIRECT_STORE;
510 use->affected_variables = affected_variables;
511 APPEND_USE (info,bb_info,use);
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;
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;
528 if (FOLLOW_ALIAS_ANALYSIS) {
529 printf ("CALL, scanning %d arguments\n", info->number_of_arguments);
531 for (i = 0; i < info->number_of_arguments; i++) {
533 //MonoInst *argument = info->arguments [i];
534 MonoAliasValue arguments_alias = info->arguments_aliases [i];
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);
540 ADD_UNIQUE_VARIABLE (info,alias_arguments,arguments_alias.variable_index);
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);
550 printf ("*** ERROR: argument %d of %d: ", argument_index, sig->param_count);
551 mono_print_tree_nl (argument);
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);
559 call_has_untracked_pointer_argument = TRUE;
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;
570 printf ("*** ERROR: argument %d of %d: ", argument_index, sig->param_count);
571 mono_print_tree_nl (argument);
577 if ((alias_arguments != NULL) || call_has_untracked_pointer_argument) {
578 MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
580 inst->ssa_op = MONO_SSA_INDIRECT_LOAD_STORE;
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;
589 APPEND_USE (info,bb_info,use);
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;
596 father_alias->type = MONO_ALIASING_TYPE_ANY;
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;
615 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
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));
621 inst->ssa_op = MONO_SSA_INDIRECT_STORE;
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));
628 inst->ssa_op = MONO_SSA_INDIRECT_STORE;
630 use->affected_variables = info->temporary_uncontrollably_aliased_variables;
631 APPEND_USE (info,bb_info,use);
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;
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);
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);
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;
652 father_alias->type = father_type;
656 if (FOLLOW_ALIAS_ANALYSIS) {
657 print_aliasing_context (&context);
664 * mono_build_aliasing_information:
665 * @cfg: Control Flow Graph
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).
672 MonoAliasingInformation*
673 mono_build_aliasing_information (MonoCompile *cfg) {
674 MonoMemPool *pool = mono_mempool_new ();
675 MonoAliasingInformation *info = mono_mempool_alloc (pool, sizeof (MonoAliasingInformation));
677 #if (DEBUG_ALIAS_ANALYSIS)
678 int verbose_level = cfg->verbose_level;
679 cfg->verbose_level = 7;
682 info->mempool = pool;
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;
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;
702 for (i = 0; i < cfg->num_bblocks; i++) {
703 MonoBasicBlock *bb = cfg->bblocks [i];
704 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
707 if (FOLLOW_ALIAS_ANALYSIS) {
708 printf ("TRAVERSING BB %d\n", bb->block_num);
712 bb_info->potential_alias_uses = NULL;
713 info->next_interesting_inst = NULL;
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);
720 update_aliasing_information_on_inst (info, bb_info, inst, NULL);
723 g_assert (info->number_of_arguments == 0);
728 for (i = 0; i < cfg->num_bblocks; i++) {
729 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
730 MonoAliasUsageInformation *use;
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;
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;
742 if (last->next != NULL) {
746 if (last->variable_index != NO_VARIABLE_INDEX) {
747 use->affected_variables = use->affected_variables->next;
748 last->next = info->uncontrollably_aliased_variables;
750 use->affected_variables = info->uncontrollably_aliased_variables;
758 if (DUMP_ALIAS_ANALYSIS) {
759 print_code_with_aliasing_information (info);
762 #if (DEBUG_ALIAS_ANALYSIS)
763 cfg->verbose_level = verbose_level;
771 mono_destroy_aliasing_information (MonoAliasingInformation *info) {
772 mono_mempool_destroy (info->mempool);
776 mono_aliasing_initialize_code_traversal (MonoAliasingInformation *info, MonoBasicBlock *bb) {
777 info->next_interesting_inst = info->bb [bb->dfn].potential_alias_uses;
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;
789 } else if (inst->ssa_op != MONO_SSA_NOP) {
790 if (inst->ssa_op == MONO_SSA_ADDRESS_TAKEN) {
793 printf ("ERROR: instruction not found '");
794 //print_tree_with_aliasing_information (info, inst);
795 mono_print_tree (inst);
797 //g_assert_not_reached ();
808 MonoLocalVariableList*
809 mono_aliasing_get_affected_variables_for_inst_in_bb (MonoAliasingInformation *info, MonoInst *inst, MonoBasicBlock *bb) {
810 MonoAliasUsageInformation *use;
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;
817 g_assert_not_reached ();
821 MonoLocalVariableList*
822 mono_aliasing_get_affected_variables_for_inst (MonoAliasingInformation *info, MonoInst *inst) {
825 for (i = 0; i < info->cfg->num_bblocks; i++) {
826 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
827 MonoAliasUsageInformation *use;
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;
835 g_assert_not_reached ();
839 #if (MONO_APPLY_DEADCE_TO_SINGLE_METHOD)
841 mono_deadce_method_name = NULL;
842 static gboolean check_deadce_method_name (MonoCompile *cfg) {
844 if (mono_deadce_method_name == NULL) {
845 mono_deadce_method_name = getenv ("MONO_DEADCE_METHOD_NAME");
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) {
854 g_free (method_name);
865 #define LOG_DEADCE (info->cfg->verbose_level > 0)
867 #define LOG_DEADCE (info->cfg->verbose_level > 4)
871 mono_aliasing_deadce_on_inst (MonoAliasingInformation *info, MonoInst **possibly_dead_assignments, MonoInst *inst) {
873 gboolean has_side_effects;
874 MonoLocalVariableList *affected_variables;
876 arity = mono_burg_arity [inst->opcode];
878 if (OP_IS_CALL (inst->opcode)) {
879 has_side_effects = TRUE;
881 has_side_effects = FALSE;
885 if (mono_aliasing_deadce_on_inst (info, possibly_dead_assignments, inst->inst_i0)) {
886 has_side_effects = TRUE;
889 if (mono_aliasing_deadce_on_inst (info, possibly_dead_assignments, inst->inst_i1)) {
890 has_side_effects = TRUE;
896 affected_variables = mono_aliasing_get_affected_variables_for_inst_traversing_code (info, inst);
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) {
903 printf ("CLEARING slot %d at inst ", affected_variable->variable_index);
904 mono_print_tree_nl (inst);
906 possibly_dead_assignments [affected_variable->variable_index] = NULL;
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) {
914 printf ("KILLING slot %d at inst ", affected_variable->variable_index);
915 mono_print_tree_nl (inst);
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;
923 //printf ("FAST DEADCE TOTAL LOCAL\n");
928 if ((! has_side_effects) && (inst->ssa_op == MONO_SSA_STORE)) {
930 printf ("FILLING slot %d with inst ", (int)inst->inst_i0->inst_c0);
931 mono_print_tree_nl (inst);
933 possibly_dead_assignments [inst->inst_i0->inst_c0] = inst;
936 return has_side_effects;
941 mono_aliasing_deadce (MonoAliasingInformation *info) {
943 MonoInst **possibly_dead_assignments;
948 possibly_dead_assignments = alloca (cfg->num_varinfo * sizeof (MonoInst*));
951 printf ("BEFORE DEADCE START\n");
952 mono_print_code (cfg);
953 printf ("BEFORE DEADCE END\n");
956 #if (MONO_APPLY_DEADCE_TO_SINGLE_METHOD)
957 if (! check_deadce_method_name (cfg)) {
959 printf ("DEADCE disabled setting MONO_DEADCE_METHOD_NAME\n");
965 for (i = 0; i < cfg->num_bblocks; i++) {
970 bb = cfg->bblocks [i];
971 memset (possibly_dead_assignments, 0, cfg->num_varinfo * sizeof (MonoInst*));
972 mono_aliasing_initialize_code_traversal (info, bb);
975 printf ("Working on BB %d\n", bb->block_num);
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) {
985 printf ("FINALLY CLEARING slot %d (JMP), inst was ", variable_index);
986 mono_print_tree_nl (possibly_dead_assignments [variable_index]);
988 possibly_dead_assignments [variable_index] = NULL;
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))) {
997 printf ("FINALLY KILLING slot %d, inst was ", variable_index);
998 mono_print_tree_nl (possibly_dead_assignments [variable_index]);
1001 //printf ("FAST DEADCE DEAD LOCAL\n");
1003 possibly_dead_assignments [variable_index]->opcode = CEE_NOP;
1004 possibly_dead_assignments [variable_index]->ssa_op = MONO_SSA_NOP;
1010 printf ("AFTER DEADCE START\n");
1011 mono_print_code (cfg);
1012 printf ("AFTER DEADCE END\n");