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 #define MONO_APPLY_DEADCE_TO_SINGLE_METHOD 0
19 #define DEBUG_DEADCE 0
21 #define DEBUG_ALIAS_ANALYSIS 0
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)
27 static const char *mono_aliasing_value_names[] = {
35 static const char *mono_stack_type_names[] = {
47 #define NO_VARIABLE_INDEX MONO_ALIASING_INVALID_VARIABLE_INDEX
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)))
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).
70 typedef struct MonoAliasingInformationContext {
73 MonoAliasValue subtree_aliases [2];
75 struct MonoAliasingInformationContext *father;
76 } MonoAliasingInformationContext;
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);
90 print_ssaop_value (int ssaop_value) {
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 (".");
99 print_aliasing_context (MonoAliasingInformationContext *context) {
100 printf ("CONTEXT: left ");
101 print_alias_value (&(context->subtree_aliases [0]));
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]));
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);
114 mono_print_tree_nl (context->inst);
118 print_tree_node (MonoInst *tree) {
122 printf (mono_inst_name (tree->opcode));
124 if (OP_IS_OUTARG (tree->opcode)) {
125 printf ("[OUT:%ld]", (long)tree->inst_c1);
128 switch (tree->opcode) {
130 printf ("[%d]", (int)tree->inst_c0);
133 printf ("[%lld]", (long long)tree->inst_l);
136 printf ("[%f]", *(double*)tree->inst_p0);
139 printf ("[%f]", *(float*)tree->inst_p0);
143 printf ("[%d]", (int)tree->inst_c0);
146 if (tree->inst_offset < 0)
147 printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
149 printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
152 printf ("[%s]", mono_arch_regname (tree->dreg));
155 printf ("[%s]", tree->inst_newa_class->name);
166 case OP_VOIDCALLVIRT: {
167 MonoCallInst *call = (MonoCallInst*)tree;
169 printf ("[%s]", call->method->name);
170 else if (call->fptr) {
171 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
173 printf ("[%s]", info->name);
175 printf ("[ARGS:%d]", call->signature->param_count);
180 printf ("[%d (", (int)tree->inst_c0);
181 for (i = 0; i < tree->inst_phi_args [0]; i++) {
184 printf ("%d", tree->inst_phi_args [i + 1]);
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);
199 case OP_CALL_HANDLER:
200 printf ("[B%d]", tree->inst_target_bb->block_num);
212 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
215 printf ("[%d]", (int)tree->inst_i0->inst_i0->inst_c0);
218 printf ("[%d]", (int)tree->inst_i0->inst_c0);
226 print_variable_list (MonoLocalVariableList* variables) {
228 while (variables != NULL) {
229 printf ("%d", variables->variable_index);
230 if (variables->next != NULL) {
233 variables = variables->next;
239 print_used_aliases(MonoInst *inst, MonoLocalVariableList* affected_variables) {
240 if (inst->ssa_op != MONO_SSA_NOP) {
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);
248 switch (inst->inst_i0->opcode) {
251 printf ("{%ld}", (long)inst->inst_i0->inst_c0);
266 print_tree_with_aliasing_information (MonoAliasingInformation *info, MonoInst *tree) {
268 MonoLocalVariableList* affected_variables;
271 printf ("NULL-INST");
275 arity = mono_burg_arity [tree->opcode];
277 print_tree_node (tree);
279 if (OP_IS_CALL (tree->opcode) && arity) {
285 print_tree_with_aliasing_information (info, tree->inst_i0);
288 print_tree_with_aliasing_information (info, tree->inst_i1);
293 affected_variables = mono_aliasing_get_affected_variables_for_inst_traversing_code (info, tree);
294 print_used_aliases (tree, affected_variables);
298 print_code_with_aliasing_information (MonoAliasingInformation *info) {
299 char *name = mono_method_full_name (info->cfg->method, TRUE);
302 printf ("ALIASING DATA START (METHOD %s)\n", name);
303 printf ("ALIASED VARIABLES: ");
304 print_variable_list (info->uncontrollably_aliased_variables);
306 for (i = 0; i < info->cfg->num_bblocks; i++) {
307 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
308 MonoAliasUsageInformation *use;
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);
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);
325 printf ("ALIASING DATA END (METHOD %s)\n", name);
330 #define APPEND_USE(info,bb_info,use) do {\
332 if ((info)->next_interesting_inst != NULL) {\
333 (info)->next_interesting_inst->next = (use);\
335 (bb_info)->potential_alias_uses = (use);\
337 (info)->next_interesting_inst = (use);\
340 #define ADD_BAD_ALIAS(info,vi) do {\
341 if (FOLLOW_ALIAS_ANALYSIS) {\
342 printf ("ADDING BAD ALIAS FOR VARIABLE %d\n", vi);\
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;\
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;\
363 (info)->arguments [(info)->number_of_arguments] = (inst);\
364 (info)->arguments_aliases [(info)->number_of_arguments] = (alias);\
365 (info)->number_of_arguments ++;\
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;\
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;\
382 update_aliasing_information_on_inst (MonoAliasingInformation *info, MonoAliasingInformationInBB *bb_info, MonoInst *inst, MonoAliasingInformationContext *father_context) {
383 MonoAliasingInformationContext context;
384 MonoAliasValue *father_alias;
387 context.father = father_context;
388 if (father_context != NULL) {
389 father_alias = &(father_context->subtree_aliases [father_context->current_subtree]);
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);
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);
406 context.subtree_aliases [1].type = MONO_ALIASING_TYPE_NO_ALIAS;
409 context.subtree_aliases [0].type = MONO_ALIASING_TYPE_NO_ALIAS;
410 context.subtree_aliases [1].type = MONO_ALIASING_TYPE_NO_ALIAS;
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;
424 father_alias->type = MONO_ALIASING_TYPE_ANY;
426 } else if (inst->ssa_op == MONO_SSA_LOAD) {
427 MonoInst *local = inst->inst_i0;
429 if (LOAD_OF_LOCAL_GIVES_POINTER (inst,local)) {
430 father_alias->type = MONO_ALIASING_TYPE_ANY;
432 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
434 } else if (OP_IS_LOAD (inst->opcode) || (inst->opcode == CEE_LDOBJ)) {
435 MonoInst *address = inst->inst_i0;
436 MonoLocalVariableList *affected_variables = NULL;
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];
442 affected_variables = &(info->variables [variable_index]);
443 if (LOAD_OF_LOCAL_GIVES_POINTER (inst,local)) {
444 father_alias->type = MONO_ALIASING_TYPE_ANY;
446 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
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];
452 affected_variables = &(info->variables [variable_index]);;
453 if (LOAD_OF_LOCAL_GIVES_POINTER (inst,local)) {
454 father_alias->type = MONO_ALIASING_TYPE_ANY;
456 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
458 } else if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD) {
459 gssize variable_index = context.subtree_aliases [0].variable_index;
461 affected_variables = &(info->variables [variable_index]);;
462 if (inst->type == STACK_MP) {
463 father_alias->type = MONO_ALIASING_TYPE_ANY;
465 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
468 if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) {
469 affected_variables = info->temporary_uncontrollably_aliased_variables;
471 if ((inst->type == STACK_MP) && (inst->inst_i0->opcode != OP_OBJADDR)) {
472 father_alias->type = MONO_ALIASING_TYPE_ANY;
474 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
478 if (affected_variables != NULL) {
479 MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
481 inst->ssa_op = MONO_SSA_INDIRECT_LOAD;
483 use->affected_variables = affected_variables;
484 APPEND_USE (info,bb_info,use);
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);
490 } else if (OP_IS_STORE (inst->opcode) || (inst->opcode == CEE_STOBJ)) {
491 MonoInst *address = inst->inst_i0;
492 MonoLocalVariableList *affected_variables = NULL;
494 if (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL) {
495 ADD_BAD_ALIAS (info, context.subtree_aliases [1].variable_index);
498 if ((address->opcode == OP_LOCAL) || (address->opcode == OP_ARG)) {
499 gssize variable_index = address->inst_c0;
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;
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;
510 if (affected_variables != NULL) {
511 MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
513 inst->ssa_op = MONO_SSA_INDIRECT_STORE;
515 use->affected_variables = affected_variables;
516 APPEND_USE (info,bb_info,use);
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;
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;
533 if (FOLLOW_ALIAS_ANALYSIS) {
534 printf ("CALL, scanning %d arguments\n", info->number_of_arguments);
536 for (i = 0; i < info->number_of_arguments; i++) {
538 //MonoInst *argument = info->arguments [i];
539 MonoAliasValue arguments_alias = info->arguments_aliases [i];
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);
545 ADD_UNIQUE_VARIABLE (info,alias_arguments,arguments_alias.variable_index);
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);
555 printf ("*** ERROR: argument %d of %d: ", argument_index, sig->param_count);
556 mono_print_tree_nl (argument);
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);
564 call_has_untracked_pointer_argument = TRUE;
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;
575 printf ("*** ERROR: argument %d of %d: ", argument_index, sig->param_count);
576 mono_print_tree_nl (argument);
582 if ((alias_arguments != NULL) || call_has_untracked_pointer_argument) {
583 MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
585 inst->ssa_op = MONO_SSA_INDIRECT_LOAD_STORE;
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;
594 APPEND_USE (info,bb_info,use);
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;
601 father_alias->type = MONO_ALIASING_TYPE_ANY;
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;
620 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
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));
626 inst->ssa_op = MONO_SSA_INDIRECT_STORE;
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));
633 inst->ssa_op = MONO_SSA_INDIRECT_STORE;
635 use->affected_variables = info->temporary_uncontrollably_aliased_variables;
636 APPEND_USE (info,bb_info,use);
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;
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);
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);
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;
657 father_alias->type = father_type;
661 if (FOLLOW_ALIAS_ANALYSIS) {
662 print_aliasing_context (&context);
669 * mono_build_aliasing_information:
670 * @cfg: Control Flow Graph
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).
677 MonoAliasingInformation*
678 mono_build_aliasing_information (MonoCompile *cfg) {
679 MonoMemPool *pool = mono_mempool_new ();
680 MonoAliasingInformation *info = mono_mempool_alloc (pool, sizeof (MonoAliasingInformation));
682 #if (DEBUG_ALIAS_ANALYSIS)
683 int verbose_level = cfg->verbose_level;
684 cfg->verbose_level = 7;
687 info->mempool = pool;
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;
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;
707 for (i = 0; i < cfg->num_bblocks; i++) {
708 MonoBasicBlock *bb = cfg->bblocks [i];
709 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
712 if (FOLLOW_ALIAS_ANALYSIS) {
713 printf ("TRAVERSING BB %d\n", bb->block_num);
717 bb_info->potential_alias_uses = NULL;
718 info->next_interesting_inst = NULL;
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);
725 update_aliasing_information_on_inst (info, bb_info, inst, NULL);
728 g_assert (info->number_of_arguments == 0);
733 for (i = 0; i < cfg->num_bblocks; i++) {
734 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
735 MonoAliasUsageInformation *use;
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;
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;
747 if (last->next != NULL) {
751 if (last->variable_index != NO_VARIABLE_INDEX) {
752 use->affected_variables = use->affected_variables->next;
753 last->next = info->uncontrollably_aliased_variables;
755 use->affected_variables = info->uncontrollably_aliased_variables;
763 if (DUMP_ALIAS_ANALYSIS) {
764 print_code_with_aliasing_information (info);
767 #if (DEBUG_ALIAS_ANALYSIS)
768 cfg->verbose_level = verbose_level;
776 mono_destroy_aliasing_information (MonoAliasingInformation *info) {
777 mono_mempool_destroy (info->mempool);
781 mono_aliasing_initialize_code_traversal (MonoAliasingInformation *info, MonoBasicBlock *bb) {
782 info->next_interesting_inst = info->bb [bb->dfn].potential_alias_uses;
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;
794 } else if (inst->ssa_op != MONO_SSA_NOP) {
795 if (inst->ssa_op == MONO_SSA_ADDRESS_TAKEN) {
798 printf ("ERROR: instruction not found '");
799 //print_tree_with_aliasing_information (info, inst);
800 mono_print_tree (inst);
802 //g_assert_not_reached ();
813 static MonoLocalVariableList*
814 mono_aliasing_get_affected_variables_for_inst_in_bb (MonoAliasingInformation *info, MonoInst *inst, MonoBasicBlock *bb) {
815 MonoAliasUsageInformation *use;
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;
822 g_assert_not_reached ();
826 MonoLocalVariableList*
827 mono_aliasing_get_affected_variables_for_inst (MonoAliasingInformation *info, MonoInst *inst) {
830 for (i = 0; i < info->cfg->num_bblocks; i++) {
831 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
832 MonoAliasUsageInformation *use;
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;
840 g_assert_not_reached ();
844 #if (MONO_APPLY_DEADCE_TO_SINGLE_METHOD)
846 mono_deadce_method_name = NULL;
847 static gboolean check_deadce_method_name (MonoCompile *cfg) {
849 if (mono_deadce_method_name == NULL) {
850 mono_deadce_method_name = getenv ("MONO_DEADCE_METHOD_NAME");
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) {
859 g_free (method_name);
870 #define LOG_DEADCE (info->cfg->verbose_level > 0)
872 #define LOG_DEADCE (info->cfg->verbose_level > 4)
876 mono_aliasing_deadce_on_inst (MonoAliasingInformation *info, MonoInst **possibly_dead_assignments, MonoInst *inst) {
878 gboolean has_side_effects;
879 MonoLocalVariableList *affected_variables;
881 arity = mono_burg_arity [inst->opcode];
883 if (OP_IS_CALL (inst->opcode)) {
884 has_side_effects = TRUE;
886 has_side_effects = FALSE;
890 if (mono_aliasing_deadce_on_inst (info, possibly_dead_assignments, inst->inst_i0)) {
891 has_side_effects = TRUE;
894 if (mono_aliasing_deadce_on_inst (info, possibly_dead_assignments, inst->inst_i1)) {
895 has_side_effects = TRUE;
901 affected_variables = mono_aliasing_get_affected_variables_for_inst_traversing_code (info, inst);
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) {
908 printf ("CLEARING slot %d at inst ", affected_variable->variable_index);
909 mono_print_tree_nl (inst);
911 possibly_dead_assignments [affected_variable->variable_index] = NULL;
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) {
919 printf ("KILLING slot %d at inst ", affected_variable->variable_index);
920 mono_print_tree_nl (inst);
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;
928 //printf ("FAST DEADCE TOTAL LOCAL\n");
933 if ((! has_side_effects) && (inst->ssa_op == MONO_SSA_STORE)) {
935 printf ("FILLING slot %d with inst ", (int)inst->inst_i0->inst_c0);
936 mono_print_tree_nl (inst);
938 possibly_dead_assignments [inst->inst_i0->inst_c0] = inst;
941 return has_side_effects;
946 mono_aliasing_deadce (MonoAliasingInformation *info) {
948 MonoInst **possibly_dead_assignments;
953 possibly_dead_assignments = alloca (cfg->num_varinfo * sizeof (MonoInst*));
956 printf ("BEFORE DEADCE START\n");
957 mono_print_code (cfg);
958 printf ("BEFORE DEADCE END\n");
961 #if (MONO_APPLY_DEADCE_TO_SINGLE_METHOD)
962 if (! check_deadce_method_name (cfg)) {
964 printf ("DEADCE disabled setting MONO_DEADCE_METHOD_NAME\n");
970 for (i = 0; i < cfg->num_bblocks; i++) {
975 bb = cfg->bblocks [i];
976 memset (possibly_dead_assignments, 0, cfg->num_varinfo * sizeof (MonoInst*));
977 mono_aliasing_initialize_code_traversal (info, bb);
980 printf ("Working on BB %d\n", bb->block_num);
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) {
990 printf ("FINALLY CLEARING slot %d (JMP), inst was ", variable_index);
991 mono_print_tree_nl (possibly_dead_assignments [variable_index]);
993 possibly_dead_assignments [variable_index] = NULL;
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))) {
1002 printf ("FINALLY KILLING slot %d, inst was ", variable_index);
1003 mono_print_tree_nl (possibly_dead_assignments [variable_index]);
1006 //printf ("FAST DEADCE DEAD LOCAL\n");
1008 possibly_dead_assignments [variable_index]->opcode = CEE_NOP;
1009 possibly_dead_assignments [variable_index]->ssa_op = MONO_SSA_NOP;
1015 printf ("AFTER DEADCE START\n");
1016 mono_print_code (cfg);
1017 printf ("AFTER DEADCE END\n");