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)==OP_CALL)||((op)==OP_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 ((op)==OP_LCONV_TO_I8)||((op)==OP_LCONV_TO_OVF_I8)||((op)==OP_LCONV_TO_OVF_I8_UN)||\
59 ((op)==OP_LCONV_TO_U8)||((op)==OP_LCONV_TO_OVF_U8)||((op)==OP_LCONV_TO_OVF_U8_UN))
60 #define OP_IS_PCONV(op) (((op)==CEE_CONV_OVF_I_UN)||((op)==CEE_CONV_OVF_U_UN)||\
61 ((op)==CEE_CONV_I)||((op)==CEE_CONV_U)||\
62 ((op)==CEE_CONV_OVF_I)||((op)==CEE_CONV_OVF_U)||\
63 ((op)==OP_LCONV_TO_I)||((op)==OP_LCONV_TO_OVF_I)||((op)==OP_LCONV_TO_OVF_I_UN)||\
64 ((op)==OP_LCONV_TO_U)||((op)==OP_LCONV_TO_OVF_U)||((op)==OP_LCONV_TO_OVF_U_UN))
65 #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)))
69 * A struct representing the context of the traversal of a MonoInst tree.
70 * Used so that "update_aliasing_information_on_inst" can understand what
71 * its caller was doing, and expecially where the current value is going
72 * to be stored (if it is an alias, we must track it).
74 typedef struct MonoAliasingInformationContext {
77 MonoAliasValue subtree_aliases [2];
79 struct MonoAliasingInformationContext *father;
80 } MonoAliasingInformationContext;
84 print_alias_value (MonoAliasValue *alias_value) {
85 printf ("[%s", mono_aliasing_value_names [alias_value->type]);
86 if ((alias_value->type == MONO_ALIASING_TYPE_LOCAL) || (alias_value->type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
87 printf (":%d]", alias_value->variable_index);
94 print_ssaop_value (int ssaop_value) {
96 if (ssaop_value & MONO_SSA_ADDRESS_TAKEN) printf ("I"); else printf (".");
97 if (ssaop_value & MONO_SSA_LOAD) printf ("R"); else printf (".");
98 if (ssaop_value & MONO_SSA_STORE) printf ("W"); else printf (".");
103 print_aliasing_context (MonoAliasingInformationContext *context) {
104 printf ("CONTEXT: left ");
105 print_alias_value (&(context->subtree_aliases [0]));
107 print_alias_value (&(context->subtree_aliases [1]));
108 if (context->father != NULL) {
109 printf (", father ");
110 print_alias_value (&(context->father->subtree_aliases [context->father->current_subtree]));
112 printf (", stack %s ", mono_stack_type_names [context->inst->type]);
113 if (context->inst->ssa_op != MONO_SSA_NOP) {
114 print_ssaop_value (context->inst->ssa_op);
118 mono_print_tree_nl (context->inst);
122 print_tree_node (MonoInst *tree) {
126 printf (mono_inst_name (tree->opcode));
128 if (OP_IS_OUTARG (tree->opcode)) {
129 printf ("[OUT:%ld]", (long)tree->inst_c1);
132 switch (tree->opcode) {
134 printf ("[%d]", (int)tree->inst_c0);
137 printf ("[%lld]", (long long)tree->inst_l);
140 printf ("[%f]", *(double*)tree->inst_p0);
143 printf ("[%f]", *(float*)tree->inst_p0);
147 printf ("[%d]", (int)tree->inst_c0);
150 if (tree->inst_offset < 0)
151 printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
153 printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
156 printf ("[%s]", mono_arch_regname (tree->dreg));
159 printf ("[%s]", tree->inst_newa_class->name);
170 case OP_VOIDCALLVIRT:
171 case OP_TRAMPCALL_VTABLE:
174 case OP_VOIDCALL_RGCTX:
177 case OP_CALL_REG_RGCTX:
178 case OP_FCALL_REG_RGCTX:
179 case OP_VOIDCALL_REG_RGCTX:
180 case OP_LCALL_REG_RGCTX:
181 case OP_VCALL_REG_RGCTX:
182 case OP_CALLVIRT_IMT:
183 case OP_VOIDCALLVIRT_IMT:
184 case OP_FCALLVIRT_IMT:
185 case OP_LCALLVIRT_IMT:
186 case OP_VCALLVIRT_IMT: {
187 MonoCallInst *call = (MonoCallInst*)tree;
189 printf ("[%s]", call->method->name);
190 else if (call->fptr) {
191 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
193 printf ("[%s]", info->name);
195 printf ("[ARGS:%d]", call->signature->param_count);
200 printf ("[%d (", (int)tree->inst_c0);
201 for (i = 0; i < tree->inst_phi_args [0]; i++) {
204 printf ("%d", tree->inst_phi_args [i + 1]);
209 case OP_LOAD_MEMBASE:
210 case OP_LOADI4_MEMBASE:
211 case OP_LOADU4_MEMBASE:
212 case OP_LOADU1_MEMBASE:
213 case OP_LOADI1_MEMBASE:
214 case OP_LOADU2_MEMBASE:
215 case OP_LOADI2_MEMBASE:
216 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
219 case OP_CALL_HANDLER:
220 printf ("[B%d]", tree->inst_target_bb->block_num);
232 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
235 printf ("[%d]", (int)tree->inst_i0->inst_i0->inst_c0);
238 printf ("[%d]", (int)tree->inst_i0->inst_c0);
246 print_variable_list (MonoLocalVariableList* variables) {
248 while (variables != NULL) {
249 printf ("%d", variables->variable_index);
250 if (variables->next != NULL) {
253 variables = variables->next;
259 print_used_aliases(MonoInst *inst, MonoLocalVariableList* affected_variables) {
260 if (inst->ssa_op != MONO_SSA_NOP) {
262 if (inst->ssa_op & MONO_SSA_ADDRESS_TAKEN) printf ("I");
263 if (inst->ssa_op & MONO_SSA_LOAD) printf ("R");
264 if (inst->ssa_op & MONO_SSA_STORE) printf ("W");
265 if (inst->ssa_op != MONO_SSA_ADDRESS_TAKEN) {
266 print_variable_list (affected_variables);
268 switch (inst->inst_i0->opcode) {
271 printf ("{%ld}", (long)inst->inst_i0->inst_c0);
286 print_tree_with_aliasing_information (MonoAliasingInformation *info, MonoInst *tree) {
288 MonoLocalVariableList* affected_variables;
291 printf ("NULL-INST");
295 arity = mono_burg_arity [tree->opcode];
297 print_tree_node (tree);
299 if (OP_IS_CALL (tree->opcode) && arity) {
305 print_tree_with_aliasing_information (info, tree->inst_i0);
308 print_tree_with_aliasing_information (info, tree->inst_i1);
313 affected_variables = mono_aliasing_get_affected_variables_for_inst_traversing_code (info, tree);
314 print_used_aliases (tree, affected_variables);
318 print_code_with_aliasing_information (MonoAliasingInformation *info) {
319 char *name = mono_method_full_name (info->cfg->method, TRUE);
322 printf ("ALIASING DATA START (METHOD %s)\n", name);
323 printf ("ALIASED VARIABLES: ");
324 print_variable_list (info->uncontrollably_aliased_variables);
326 for (i = 0; i < info->cfg->num_bblocks; i++) {
327 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
328 MonoAliasUsageInformation *use;
331 printf ("CODE FOR BB %d\n", bb_info->bb->block_num);
332 mono_aliasing_initialize_code_traversal (info, bb_info->bb);
333 MONO_BB_FOR_EACH_INS (bb_info->bb, inst) {
334 print_tree_with_aliasing_information (info, inst);
338 printf ("USES FOR BB %d\n", bb_info->bb->block_num);
339 for (use = bb_info->potential_alias_uses; use != NULL; use = use->next) {
340 mono_print_tree (use->inst);
341 print_used_aliases (use->inst, use->affected_variables);
345 printf ("ALIASING DATA END (METHOD %s)\n", name);
350 #define APPEND_USE(info,bb_info,use) do {\
352 if ((info)->next_interesting_inst != NULL) {\
353 (info)->next_interesting_inst->next = (use);\
355 (bb_info)->potential_alias_uses = (use);\
357 (info)->next_interesting_inst = (use);\
360 #define ADD_BAD_ALIAS(info,vi) do {\
361 if (FOLLOW_ALIAS_ANALYSIS) {\
362 printf ("ADDING BAD ALIAS FOR VARIABLE %d\n", vi);\
364 if (! ((info)->variable_is_uncontrollably_aliased [(vi)])) {\
365 MonoLocalVariableList *variable = mono_mempool_alloc ((info)->mempool, sizeof (MonoLocalVariableList));\
366 variable->variable_index = (vi);\
367 variable->next = (info)->uncontrollably_aliased_variables;\
368 (info)->uncontrollably_aliased_variables = variable;\
369 (info)->variable_is_uncontrollably_aliased [(vi)] = TRUE;\
373 #define ADD_ARGUMGENT(info,inst,alias) do {\
374 if ((info)->number_of_arguments == (info)->arguments_capacity) {\
375 MonoInst **new_arguments = mono_mempool_alloc ((info)->mempool, sizeof (MonoInst*) * ((info)->arguments_capacity * 2));\
376 MonoAliasValue *new_arguments_aliases = mono_mempool_alloc ((info)->mempool, sizeof (MonoAliasValue) * ((info)->arguments_capacity * 2));\
377 memcpy (new_arguments, (info)->arguments, sizeof (MonoInst*) * ((info)->arguments_capacity));\
378 memcpy (new_arguments_aliases, (info)->arguments_aliases, sizeof (MonoAliasValue) * ((info)->arguments_capacity));\
379 (info)->arguments = new_arguments;\
380 (info)->arguments_aliases = new_arguments_aliases;\
381 (info)->arguments_capacity = (info)->arguments_capacity * 2;\
383 (info)->arguments [(info)->number_of_arguments] = (inst);\
384 (info)->arguments_aliases [(info)->number_of_arguments] = (alias);\
385 (info)->number_of_arguments ++;\
388 #define ADD_UNIQUE_VARIABLE(info,list,vi) do {\
389 MonoLocalVariableList* target_element = (list);\
390 while ((target_element != NULL) && (target_element->variable_index != (vi))) {\
391 target_element = target_element->next;\
393 if (target_element == NULL) {\
394 target_element = mono_mempool_alloc ((info)->mempool, sizeof (MonoLocalVariableList));\
395 target_element->variable_index = (vi);\
396 target_element->next = (list);\
397 (list) = target_element;\
402 update_aliasing_information_on_inst (MonoAliasingInformation *info, MonoAliasingInformationInBB *bb_info, MonoInst *inst, MonoAliasingInformationContext *father_context) {
403 MonoAliasingInformationContext context;
404 MonoAliasValue *father_alias;
407 context.father = father_context;
408 if (father_context != NULL) {
409 father_alias = &(father_context->subtree_aliases [father_context->current_subtree]);
414 if (mono_burg_arity [inst->opcode]) {
415 context.current_subtree = 0;
416 context.subtree_aliases [0].type = MONO_ALIASING_TYPE_ANY;
417 context.subtree_aliases [0].variable_index = NO_VARIABLE_INDEX;
418 update_aliasing_information_on_inst (info, bb_info, inst->inst_i0, &context);
420 if (mono_burg_arity [inst->opcode] > 1) {
421 context.current_subtree = 1;
422 context.subtree_aliases [1].type = MONO_ALIASING_TYPE_ANY;
423 context.subtree_aliases [1].variable_index = NO_VARIABLE_INDEX;
424 update_aliasing_information_on_inst (info, bb_info, inst->inst_i1, &context);
426 context.subtree_aliases [1].type = MONO_ALIASING_TYPE_NO_ALIAS;
429 context.subtree_aliases [0].type = MONO_ALIASING_TYPE_NO_ALIAS;
430 context.subtree_aliases [1].type = MONO_ALIASING_TYPE_NO_ALIAS;
433 if (OP_IS_CONST (inst->opcode)) {
434 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
435 } else if (inst->ssa_op == MONO_SSA_ADDRESS_TAKEN) {
436 MonoInst *local = inst->inst_i0;
437 if ((local->opcode == OP_LOCAL) || (local->opcode == OP_ARG)) {
438 gssize variable_index = local->inst_c0;
439 father_alias->type = MONO_ALIASING_TYPE_LOCAL;
440 father_alias->variable_index = variable_index;
441 } else if (local->opcode == OP_RETARG) {
442 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
444 father_alias->type = MONO_ALIASING_TYPE_ANY;
446 } else if (inst->ssa_op == MONO_SSA_LOAD) {
447 MonoInst *local = inst->inst_i0;
449 if (LOAD_OF_LOCAL_GIVES_POINTER (inst,local)) {
450 father_alias->type = MONO_ALIASING_TYPE_ANY;
452 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
454 } else if (OP_IS_LOAD (inst->opcode) || (inst->opcode == CEE_LDOBJ)) {
455 MonoInst *address = inst->inst_i0;
456 MonoLocalVariableList *affected_variables = NULL;
458 if ((address->opcode == OP_LOCAL) || (address->opcode == OP_ARG)) {
459 gssize variable_index = address->inst_c0;
460 MonoInst *local = info->cfg->varinfo [variable_index];
462 affected_variables = &(info->variables [variable_index]);
463 if (LOAD_OF_LOCAL_GIVES_POINTER (inst,local)) {
464 father_alias->type = MONO_ALIASING_TYPE_ANY;
466 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
468 } else if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL) {
469 gssize variable_index = context.subtree_aliases [0].variable_index;
470 MonoInst *local = info->cfg->varinfo [variable_index];
472 affected_variables = &(info->variables [variable_index]);;
473 if (LOAD_OF_LOCAL_GIVES_POINTER (inst,local)) {
474 father_alias->type = MONO_ALIASING_TYPE_ANY;
476 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
478 } else if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD) {
479 gssize variable_index = context.subtree_aliases [0].variable_index;
481 affected_variables = &(info->variables [variable_index]);;
482 if (inst->type == STACK_MP) {
483 father_alias->type = MONO_ALIASING_TYPE_ANY;
485 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
488 if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) {
489 affected_variables = info->temporary_uncontrollably_aliased_variables;
491 if ((inst->type == STACK_MP) && (inst->inst_i0->opcode != OP_OBJADDR)) {
492 father_alias->type = MONO_ALIASING_TYPE_ANY;
494 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
498 if (affected_variables != NULL) {
499 MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
501 inst->ssa_op = MONO_SSA_INDIRECT_LOAD;
503 use->affected_variables = affected_variables;
504 APPEND_USE (info,bb_info,use);
506 } else if (inst->ssa_op == MONO_SSA_STORE) {
507 if (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL) {
508 ADD_BAD_ALIAS (info, context.subtree_aliases [1].variable_index);
510 } else if (OP_IS_STORE (inst->opcode) || (inst->opcode == CEE_STOBJ)) {
511 MonoInst *address = inst->inst_i0;
512 MonoLocalVariableList *affected_variables = NULL;
514 if (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL) {
515 ADD_BAD_ALIAS (info, context.subtree_aliases [1].variable_index);
518 if ((address->opcode == OP_LOCAL) || (address->opcode == OP_ARG)) {
519 gssize variable_index = address->inst_c0;
521 affected_variables = &(info->variables [variable_index]);
522 } else if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
523 gssize variable_index = context.subtree_aliases [0].variable_index;
525 affected_variables = &(info->variables [variable_index]);;
526 } else if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) {
527 affected_variables = info->temporary_uncontrollably_aliased_variables;
530 if (affected_variables != NULL) {
531 MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
533 inst->ssa_op = MONO_SSA_INDIRECT_STORE;
535 use->affected_variables = affected_variables;
536 APPEND_USE (info,bb_info,use);
538 } else if (OP_IS_OUTARG (inst->opcode)) {
539 ADD_ARGUMGENT (info,inst,context.subtree_aliases [0]);
540 } else if (OP_IS_CALL (inst->opcode)) {
541 MonoCallInst *call = (MonoCallInst *) inst;
542 MonoMethodSignature *sig = call->signature;
543 gboolean call_has_untracked_pointer_argument = FALSE;
544 MonoLocalVariableList *alias_arguments = NULL;
547 if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
548 ADD_UNIQUE_VARIABLE (info,alias_arguments,context.subtree_aliases [0].variable_index);
549 } else if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) {
550 call_has_untracked_pointer_argument = TRUE;
553 if (FOLLOW_ALIAS_ANALYSIS) {
554 printf ("CALL, scanning %d arguments\n", info->number_of_arguments);
556 for (i = 0; i < info->number_of_arguments; i++) {
558 //MonoInst *argument = info->arguments [i];
559 MonoAliasValue arguments_alias = info->arguments_aliases [i];
561 if ((arguments_alias.type == MONO_ALIASING_TYPE_LOCAL) || (arguments_alias.type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
562 if (FOLLOW_ALIAS_ANALYSIS) {
563 printf ("CALL, argument %d passes the address of local %d\n", i, arguments_alias.variable_index);
565 ADD_UNIQUE_VARIABLE (info,alias_arguments,arguments_alias.variable_index);
568 if (((arguments_alias.type == MONO_ALIASING_TYPE_LOCAL)) && (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]->byref)) {
572 ADD_BAD_ALIAS (info, arguments_alias.variable_index);
575 printf ("*** ERROR: argument %d of %d: ", argument_index, sig->param_count);
576 mono_print_tree_nl (argument);
580 } else if (arguments_alias.type == MONO_ALIASING_TYPE_ANY) {
581 if (FOLLOW_ALIAS_ANALYSIS) {
582 printf ("CALL, argument %d could pass the address of any local\n", i);
584 call_has_untracked_pointer_argument = TRUE;
588 else if (argument->inst_c1 > 0) {
589 int argument_index = argument->inst_c1 - 1;
590 if (argument_index < sig->param_count) {
591 if (sig->params [argument_index]->type == MONO_TYPE_PTR) {
592 call_has_untracked_pointer_argument = TRUE;
595 printf ("*** ERROR: argument %d of %d: ", argument_index, sig->param_count);
596 mono_print_tree_nl (argument);
602 if ((alias_arguments != NULL) || call_has_untracked_pointer_argument) {
603 MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
605 inst->ssa_op = MONO_SSA_INDIRECT_LOAD_STORE;
607 use->affected_variables = alias_arguments;
608 if (call_has_untracked_pointer_argument) {
609 MonoLocalVariableList *untracked_element = mono_mempool_alloc ((info)->mempool, sizeof (MonoLocalVariableList));
610 untracked_element->variable_index = NO_VARIABLE_INDEX;
611 untracked_element->next = use->affected_variables;
612 use->affected_variables = untracked_element;
614 APPEND_USE (info,bb_info,use);
617 if ((sig->ret != NULL) && (father_alias != NULL)) {
618 if (sig->ret->type != MONO_TYPE_PTR) {
619 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
621 father_alias->type = MONO_ALIASING_TYPE_ANY;
625 info->number_of_arguments = 0;
626 } else if ((inst->opcode == CEE_ADD) || (inst->opcode == OP_LADD)){
627 if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
628 int variable_index = context.subtree_aliases [0].variable_index;
629 //ADD_BAD_ALIAS (info, variable_index);
630 father_alias->type = MONO_ALIASING_TYPE_LOCAL_FIELD;
631 father_alias->variable_index = variable_index;
632 } else if ((context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
633 int variable_index = context.subtree_aliases [1].variable_index;
634 //ADD_BAD_ALIAS (info, variable_index);
635 father_alias->type = MONO_ALIASING_TYPE_LOCAL_FIELD;
636 father_alias->variable_index = variable_index;
637 } else if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) || (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_ANY)) {
638 father_alias->type = MONO_ALIASING_TYPE_ANY;
640 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
642 } else if ((inst->opcode == OP_MEMCPY) || (inst->opcode == OP_MEMSET)) {
643 if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
644 MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
646 inst->ssa_op = MONO_SSA_INDIRECT_STORE;
648 use->affected_variables = &(info->variables [context.subtree_aliases [0].variable_index]);
649 APPEND_USE (info,bb_info,use);
650 } else if (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) {
651 MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
653 inst->ssa_op = MONO_SSA_INDIRECT_STORE;
655 use->affected_variables = info->temporary_uncontrollably_aliased_variables;
656 APPEND_USE (info,bb_info,use);
658 } else if ((inst->opcode == OP_UNBOXCAST) || OP_IS_PCONV (inst->opcode) || OP_IS_ICONV (inst->opcode)) {
659 father_alias->type = context.subtree_aliases [0].type;
660 father_alias->variable_index = context.subtree_aliases [0].variable_index;
661 } else if ((inst->opcode == CEE_LDELEMA) || (inst->opcode == OP_COMPARE) || (inst->opcode == OP_SWITCH)) {
662 if (father_alias != NULL) {
663 father_alias->type = MONO_ALIASING_TYPE_NO_ALIAS;
666 MonoAliasType father_type = MONO_ALIASING_TYPE_NO_ALIAS;
667 MonoLocalVariableList *affected_variables = NULL;
669 if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [0].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
670 affected_variables = &(info->variables [context.subtree_aliases [0].variable_index]);
671 ADD_BAD_ALIAS (info, context.subtree_aliases [0].variable_index);
673 if ((context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL) || (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_LOCAL_FIELD)) {
674 if (affected_variables == NULL) {
675 affected_variables = &(info->variables [context.subtree_aliases [1].variable_index]);
676 } else if (affected_variables->variable_index != context.subtree_aliases [1].variable_index) {
677 int previous_index = affected_variables->variable_index;
678 affected_variables = NULL;
679 ADD_UNIQUE_VARIABLE (info, affected_variables, previous_index);
680 ADD_UNIQUE_VARIABLE (info, affected_variables, context.subtree_aliases [1].variable_index);
682 ADD_BAD_ALIAS (info, context.subtree_aliases [1].variable_index);
685 if (affected_variables != NULL) {
686 MonoAliasUsageInformation *use = mono_mempool_alloc (info->mempool, sizeof (MonoAliasUsageInformation));
688 inst->ssa_op = MONO_SSA_INDIRECT_LOAD_STORE;
690 use->affected_variables = affected_variables;
691 APPEND_USE (info, bb_info, use);
694 if (father_alias != NULL) {
695 if ((context.subtree_aliases [0].type == MONO_ALIASING_TYPE_ANY) || (context.subtree_aliases [1].type == MONO_ALIASING_TYPE_ANY)) {
696 father_type = MONO_ALIASING_TYPE_ANY;
698 father_alias->type = father_type;
702 if (FOLLOW_ALIAS_ANALYSIS) {
703 print_aliasing_context (&context);
710 * mono_build_aliasing_information:
711 * @cfg: Control Flow Graph
713 * Builds the aliasing information in a cfg.
714 * After this has run, all MonoInst.ssa_op fields will be properly
715 * set (it will use the MONO_SSA_ADDRESS_TAKEN, MONO_SSA_LOAD and
716 * MONO_SSA_STORE values as a starting point).
718 MonoAliasingInformation*
719 mono_build_aliasing_information (MonoCompile *cfg) {
720 MonoMemPool *pool = mono_mempool_new ();
721 MonoAliasingInformation *info = mono_mempool_alloc (pool, sizeof (MonoAliasingInformation));
723 #if (DEBUG_ALIAS_ANALYSIS)
724 int verbose_level = cfg->verbose_level;
725 cfg->verbose_level = 7;
728 info->mempool = pool;
730 info->bb = mono_mempool_alloc (pool, sizeof (MonoAliasingInformationInBB) * cfg->num_bblocks);
731 info->uncontrollably_aliased_variables = NULL;
732 info->next_interesting_inst = NULL;
733 info->variables = mono_mempool_alloc (pool, sizeof (MonoLocalVariableList) * cfg->num_varinfo);
734 info->variable_is_uncontrollably_aliased = mono_mempool_alloc (pool, sizeof (gboolean) * cfg->num_varinfo);
735 for (i = 0; i < cfg->num_varinfo; i++) {
736 info->variables [i].next = NULL;
737 info->variables [i].variable_index = i;
738 info->variable_is_uncontrollably_aliased [i] = FALSE;
740 info->temporary_uncontrollably_aliased_variables = mono_mempool_alloc (pool, sizeof (MonoLocalVariableList));
741 info->temporary_uncontrollably_aliased_variables->next = NULL;
742 info->temporary_uncontrollably_aliased_variables->variable_index = NO_VARIABLE_INDEX;
743 info->arguments = mono_mempool_alloc (pool, sizeof (MonoInst*) * 16);
744 info->arguments_aliases = mono_mempool_alloc (pool, sizeof (MonoAliasValue) * 16);
745 info->arguments_capacity = 16;
746 info->number_of_arguments = 0;
748 for (i = 0; i < cfg->num_bblocks; i++) {
749 MonoBasicBlock *bb = cfg->bblocks [i];
750 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
753 if (FOLLOW_ALIAS_ANALYSIS) {
754 printf ("TRAVERSING BB %d\n", bb->block_num);
758 bb_info->potential_alias_uses = NULL;
759 info->next_interesting_inst = NULL;
761 MONO_BB_FOR_EACH_INS (bb, inst) {
762 if (FOLLOW_ALIAS_ANALYSIS) {
763 printf ("TRAVERSING INST: ");
764 mono_print_tree_nl (inst);
766 update_aliasing_information_on_inst (info, bb_info, inst, NULL);
769 g_assert (info->number_of_arguments == 0);
774 for (i = 0; i < cfg->num_bblocks; i++) {
775 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
776 MonoAliasUsageInformation *use;
778 for (use = bb_info->potential_alias_uses; use != NULL; use = use->next) {
779 if ((use->affected_variables != NULL) && (use->affected_variables->variable_index == NO_VARIABLE_INDEX)) {
780 if (use->affected_variables->next == NULL) {
781 use->affected_variables = info->uncontrollably_aliased_variables;
783 MonoLocalVariableList *last = use->affected_variables;
784 while (last->next != NULL) {
785 while (last->next && info->variable_is_uncontrollably_aliased [last->next->variable_index]) {
786 last->next = last->next->next;
788 if (last->next != NULL) {
792 if (last->variable_index != NO_VARIABLE_INDEX) {
793 use->affected_variables = use->affected_variables->next;
794 last->next = info->uncontrollably_aliased_variables;
796 use->affected_variables = info->uncontrollably_aliased_variables;
804 if (DUMP_ALIAS_ANALYSIS) {
805 print_code_with_aliasing_information (info);
808 #if (DEBUG_ALIAS_ANALYSIS)
809 cfg->verbose_level = verbose_level;
817 mono_destroy_aliasing_information (MonoAliasingInformation *info) {
818 mono_mempool_destroy (info->mempool);
822 mono_aliasing_initialize_code_traversal (MonoAliasingInformation *info, MonoBasicBlock *bb) {
823 info->next_interesting_inst = info->bb [bb->dfn].potential_alias_uses;
826 MonoLocalVariableList*
827 mono_aliasing_get_affected_variables_for_inst_traversing_code (MonoAliasingInformation *info, MonoInst *inst) {
828 if ((inst->ssa_op == MONO_SSA_LOAD) || (inst->ssa_op == MONO_SSA_STORE)) {
829 return &(info->variables [inst->inst_i0->inst_c0]);
830 } else if (info->next_interesting_inst != NULL) {
831 if (inst == info->next_interesting_inst->inst) {
832 MonoLocalVariableList *result = info->next_interesting_inst->affected_variables;
833 info->next_interesting_inst = info->next_interesting_inst->next;
835 } else if (inst->ssa_op != MONO_SSA_NOP) {
836 if (inst->ssa_op == MONO_SSA_ADDRESS_TAKEN) {
839 printf ("ERROR: instruction not found '");
840 //print_tree_with_aliasing_information (info, inst);
841 mono_print_tree (inst);
843 //g_assert_not_reached ();
855 static MonoLocalVariableList*
856 mono_aliasing_get_affected_variables_for_inst_in_bb (MonoAliasingInformation *info, MonoInst *inst, MonoBasicBlock *bb) {
857 MonoAliasUsageInformation *use;
859 for (use = info->bb [bb->dfn].potential_alias_uses; use != NULL; use = use->next) {
860 if (use->inst == inst) {
861 return use->affected_variables;
864 g_assert_not_reached ();
869 MonoLocalVariableList*
870 mono_aliasing_get_affected_variables_for_inst (MonoAliasingInformation *info, MonoInst *inst) {
873 for (i = 0; i < info->cfg->num_bblocks; i++) {
874 MonoAliasingInformationInBB *bb_info = &(info->bb [i]);
875 MonoAliasUsageInformation *use;
877 for (use = info->bb [bb_info->bb->dfn].potential_alias_uses; use != NULL; use = use->next) {
878 if (use->inst == inst) {
879 return use->affected_variables;
883 g_assert_not_reached ();
887 #if (MONO_APPLY_DEADCE_TO_SINGLE_METHOD)
889 mono_deadce_method_name = NULL;
890 static gboolean check_deadce_method_name (MonoCompile *cfg) {
892 if (mono_deadce_method_name == NULL) {
893 mono_deadce_method_name = getenv ("MONO_DEADCE_METHOD_NAME");
895 if (mono_deadce_method_name != NULL) {
896 char *method_name = mono_method_full_name (cfg->method, TRUE);
897 if (strstr (method_name, mono_deadce_method_name) != NULL) {
902 g_free (method_name);
913 #define LOG_DEADCE (info->cfg->verbose_level > 0)
915 #define LOG_DEADCE (info->cfg->verbose_level > 4)
919 mono_aliasing_deadce_on_inst (MonoAliasingInformation *info, MonoInst **possibly_dead_assignments, MonoInst *inst) {
921 gboolean has_side_effects;
922 MonoLocalVariableList *affected_variables;
924 arity = mono_burg_arity [inst->opcode];
926 switch (inst->opcode) {
927 #define OPDEF(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) case a1:
928 #include "simple-cee-ops.h"
930 #define MINI_OP(a1,a2) case a1:
931 #include "simple-mini-ops.h"
933 has_side_effects = FALSE;
936 has_side_effects = TRUE;
940 if (mono_aliasing_deadce_on_inst (info, possibly_dead_assignments, inst->inst_i0)) {
941 has_side_effects = TRUE;
944 if (mono_aliasing_deadce_on_inst (info, possibly_dead_assignments, inst->inst_i1)) {
945 has_side_effects = TRUE;
951 affected_variables = mono_aliasing_get_affected_variables_for_inst_traversing_code (info, inst);
953 if (affected_variables != NULL) {
954 if (inst->ssa_op & MONO_SSA_LOAD) {
955 MonoLocalVariableList *affected_variable;
956 for (affected_variable = affected_variables; affected_variable != NULL; affected_variable = affected_variable->next) {
958 printf ("CLEARING slot %d at inst ", affected_variable->variable_index);
959 mono_print_tree_nl (inst);
961 possibly_dead_assignments [affected_variable->variable_index] = NULL;
964 if (inst->ssa_op & MONO_SSA_STORE) {
965 MonoLocalVariableList *affected_variable;
966 for (affected_variable = affected_variables; affected_variable != NULL; affected_variable = affected_variable->next) {
967 if (possibly_dead_assignments [affected_variable->variable_index] != NULL) {
969 printf ("KILLING slot %d at inst ", affected_variable->variable_index);
970 mono_print_tree_nl (inst);
972 possibly_dead_assignments [affected_variable->variable_index]->opcode = OP_NOP;
973 possibly_dead_assignments [affected_variable->variable_index]->ssa_op = MONO_SSA_NOP;
974 possibly_dead_assignments [affected_variable->variable_index] = NULL;
978 //printf ("FAST DEADCE TOTAL LOCAL\n");
983 if ((! has_side_effects) && (inst->ssa_op == MONO_SSA_STORE)) {
985 printf ("FILLING slot %d with inst ", (int)inst->inst_i0->inst_c0);
986 mono_print_tree_nl (inst);
988 possibly_dead_assignments [inst->inst_i0->inst_c0] = inst;
991 return has_side_effects;
996 mono_aliasing_deadce (MonoAliasingInformation *info) {
998 MonoInst **possibly_dead_assignments;
1003 possibly_dead_assignments = alloca (cfg->num_varinfo * sizeof (MonoInst*));
1006 mono_print_code (cfg, "BEFORE DEADCE START");
1009 #if (MONO_APPLY_DEADCE_TO_SINGLE_METHOD)
1010 if (! check_deadce_method_name (cfg)) {
1012 printf ("DEADCE disabled setting MONO_DEADCE_METHOD_NAME\n");
1018 for (i = 0; i < cfg->num_bblocks; i++) {
1023 bb = cfg->bblocks [i];
1024 memset (possibly_dead_assignments, 0, cfg->num_varinfo * sizeof (MonoInst*));
1025 mono_aliasing_initialize_code_traversal (info, bb);
1028 printf ("Working on BB %d\n", bb->block_num);
1031 MONO_BB_FOR_EACH_INS (bb, inst) {
1032 mono_aliasing_deadce_on_inst (info, possibly_dead_assignments, inst);
1033 if (inst->opcode == OP_JMP) {
1034 /* Keep arguments live! */
1035 for (variable_index = 0; variable_index < cfg->num_varinfo; variable_index++) {
1036 if (cfg->varinfo [variable_index]->opcode == OP_ARG) {
1038 printf ("FINALLY CLEARING slot %d (JMP), inst was ", variable_index);
1039 mono_print_tree_nl (possibly_dead_assignments [variable_index]);
1041 possibly_dead_assignments [variable_index] = NULL;
1047 for (variable_index = 0; variable_index < cfg->num_varinfo; variable_index++) {
1048 if ((possibly_dead_assignments [variable_index] != NULL) && (! mono_bitset_test (bb->live_out_set, variable_index))) {
1050 printf ("FINALLY KILLING slot %d, inst was ", variable_index);
1051 mono_print_tree_nl (possibly_dead_assignments [variable_index]);
1054 //printf ("FAST DEADCE DEAD LOCAL\n");
1056 possibly_dead_assignments [variable_index]->opcode = OP_NOP;
1057 possibly_dead_assignments [variable_index]->ssa_op = MONO_SSA_NOP;
1063 mono_print_code (cfg, "AFTER DEADCE");