2 * ssapre.h: SSA Partial Redundancy Elimination
5 * Massimiliano Mantione (massi@ximian.com)
7 * (C) 2004 Novell, Inc. http://www.novell.com
13 #include <mono/metadata/debug-helpers.h>
14 #include <mono/metadata/opcodes.h>
20 extern guint8 mono_burg_arity [];
22 /* Logging conditions */
23 #define DUMP_LEVEL (4)
24 #define TRACE_LEVEL (3)
25 #define STATISTICS_LEVEL (2)
27 #define DUMP_SSAPRE (area->cfg->verbose_level >= DUMP_LEVEL)
28 #define TRACE_SSAPRE (area->cfg->verbose_level >= TRACE_LEVEL)
29 #define STATISTICS_SSAPRE (area->cfg->verbose_level >= STATISTICS_LEVEL)
30 #define LOG_SSAPRE (area->cfg->verbose_level >= LOG_LEVEL)
32 /* "Bottom" symbol definition (see paper) */
33 #define BOTTOM_REDUNDANCY_CLASS (-1)
35 /* Various printing functions... */
37 print_argument (MonoSsapreExpressionArgument *argument) {
38 switch (argument->type) {
39 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY:
42 case MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT:
45 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE:
46 printf ("ORIGINAL_VARIABLE %d", argument->argument.original_variable);
48 case MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE:
49 printf ("SSA_VARIABLE %d", argument->argument.ssa_variable);
51 case MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT:
52 printf ("INTEGER_CONSTANT %d", argument->argument.integer_constant);
54 case MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT:
55 printf ("LONG_COSTANT %lld", *(argument->argument.long_constant));
57 case MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT:
58 printf ("FLOAT_COSTANT %f", *(argument->argument.float_constant));
60 case MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT:
61 printf ("DOUBLE_COSTANT %f", *(argument->argument.double_constant));
64 printf ("UNKNOWN: %d", argument->type);
70 print_expression_description (MonoSsapreExpressionDescription *expression_description) {
71 if (expression_description->opcode != 0) {
72 printf ("%s ([", mono_inst_name (expression_description->opcode) );
73 print_argument (&(expression_description->left_argument));
75 print_argument (&(expression_description->right_argument));
82 #define GBOOLEAN_TO_STRING(b) ((b)?"TRUE":"FALSE")
85 print_expression_occurrence (MonoSsapreExpressionOccurrence *occurrence, int number) {
86 printf (" ([%d][bb %d [ID %d]][class %d]: ", number, occurrence->bb_info->cfg_dfn, occurrence->bb_info->bb->block_num, occurrence->redundancy_class);
87 print_expression_description (&(occurrence->description));
88 if (occurrence->is_first_in_bb) {
89 printf (" [FIRST in BB]");
91 if (occurrence->is_last_in_bb) {
92 printf (" [LAST in BB]");
94 printf (" (save = %s)", GBOOLEAN_TO_STRING (occurrence->save));
95 printf (" (reload = %s)", GBOOLEAN_TO_STRING (occurrence->reload));
97 occurrence = occurrence->next;
101 print_expression_occurrences (MonoSsapreExpressionOccurrence *occurrences) {
103 while (occurrences != NULL) {
105 print_expression_occurrence (occurrences, i);
106 occurrences = occurrences->next;
111 print_worklist (MonoSsapreExpression *expression) {
112 if (expression != NULL) {
113 print_worklist (expression->previous);
115 printf ("{%d}: ", expression->tree_size);
116 print_expression_description (&(expression->description));
118 print_expression_occurrences (expression->occurrences);
120 print_worklist (expression->next);
125 print_bb_info (MonoSsapreBBInfo *bb_info, gboolean print_occurrences) {
127 MonoSsapreExpressionOccurrence *current_occurrence = bb_info->first_expression_in_bb;
129 printf ("bb %d [ID %d]: IN { ", bb_info->cfg_dfn, bb_info->bb->block_num);
130 for (i = 0; i < bb_info->in_count; i++) {
131 printf ("%d [ID %d] ", bb_info->in_bb [i]->cfg_dfn, bb_info->in_bb [i]->bb->block_num);
134 for (i = 0; i < bb_info->out_count; i++) {
135 printf ("%d [ID %d] ", bb_info->out_bb [i]->cfg_dfn, bb_info->out_bb [i]->bb->block_num);
138 if (bb_info->next_interesting_bb != NULL) {
139 printf (", NEXT %d [ID %d]", bb_info->next_interesting_bb->cfg_dfn, bb_info->next_interesting_bb->bb->block_num);
142 if (bb_info->has_phi) {
143 printf (" PHI, class %d [ ", bb_info->phi_redundancy_class);
144 for (i = 0; i < bb_info->in_count; i++) {
145 int argument_class = bb_info->phi_arguments_classes [i];
146 if (argument_class != BOTTOM_REDUNDANCY_CLASS) {
147 printf ("%d ", argument_class);
152 printf ("]\n(phi_defines_a_real_occurrence:%s) (phi_is_down_safe:%s) (phi_can_be_available:%s) (phi_is_later:%s)\n",
153 GBOOLEAN_TO_STRING (bb_info->phi_defines_a_real_occurrence), GBOOLEAN_TO_STRING (bb_info->phi_is_down_safe),
154 GBOOLEAN_TO_STRING (bb_info->phi_can_be_available), GBOOLEAN_TO_STRING (bb_info->phi_is_later));
156 if (print_occurrences) {
158 while ((current_occurrence != NULL) && (current_occurrence->bb_info == bb_info)) {
159 print_expression_occurrence (current_occurrence, i);
160 current_occurrence = current_occurrence->next;
164 if (bb_info->has_phi_argument) {
165 printf (" PHI ARGUMENT, class ");
166 if (bb_info->phi_argument_class != BOTTOM_REDUNDANCY_CLASS) {
167 printf ("%d ", bb_info->phi_argument_class);
171 if (bb_info->phi_argument_defined_by_real_occurrence != NULL) {
172 printf ("(Defined by real occurrence %d)", bb_info->phi_argument_defined_by_real_occurrence->redundancy_class);
173 } else if (bb_info->phi_argument_defined_by_phi != NULL) {
174 printf ("(Defined by phi %d)", bb_info->phi_argument_defined_by_phi->phi_redundancy_class);
176 printf ("(Undefined)");
178 printf (" (real occurrence arguments: left ");
179 if (bb_info->phi_argument_left_argument_version != BOTTOM_REDUNDANCY_CLASS) {
180 printf ("%d ", bb_info->phi_argument_left_argument_version);
185 if (bb_info->phi_argument_right_argument_version != BOTTOM_REDUNDANCY_CLASS) {
186 printf ("%d ", bb_info->phi_argument_right_argument_version);
190 printf (")\n(phi_argument_has_real_use:%s) (phi_argument_needs_insert:%s) (phi_argument_has_been_processed:%s)\n",
191 GBOOLEAN_TO_STRING (bb_info->phi_argument_has_real_use), GBOOLEAN_TO_STRING (bb_info->phi_argument_needs_insert),
192 GBOOLEAN_TO_STRING (bb_info->phi_argument_has_been_processed));
197 print_bb_infos (MonoSsapreWorkArea *area) {
199 for (i = 0; i < area->num_bblocks; i++) {
200 MonoSsapreBBInfo *bb_info = &(area->bb_infos [i]);
201 print_bb_info (bb_info, TRUE);
206 print_interesting_bb_infos (MonoSsapreWorkArea *area) {
207 MonoSsapreBBInfo *current_bb;
209 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
210 print_bb_info (current_bb, FALSE);
214 static void dump_code (MonoSsapreWorkArea *area) {
217 for (i = 0; i < area->num_bblocks; i++) {
218 MonoSsapreBBInfo *current_bb = &(area->bb_infos [i]);
219 MonoInst *current_inst;
221 print_bb_info (current_bb, TRUE);
222 for (current_inst = current_bb->bb->code; current_inst != NULL; current_inst = current_inst->next) {
223 mono_print_tree_nl (current_inst);
229 * Given a MonoInst, it tries to describe it as an expression argument.
230 * If this is not possible, the result will be of type
231 * MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY.
234 analyze_argument (MonoInst *argument, MonoSsapreExpressionArgument *result) {
235 switch (argument->opcode) {
247 analyze_argument (argument->inst_left, result);
250 result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT;
251 result->argument.integer_constant = argument->inst_c0;
254 result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT;
255 result->argument.long_constant = &(argument->inst_l);
258 result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT;
259 result->argument.float_constant = (float*)argument->inst_p0;
262 result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT;
263 result->argument.double_constant = (double*)argument->inst_p0;
267 result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE;
268 result->argument.ssa_variable = argument->inst_c0;
271 result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
276 * Given a MonoInst, it tries to describe it as an expression.
277 * If this is not possible, the result will have opcode 0.
280 analyze_expression (MonoInst *expression, MonoSsapreExpressionDescription *result) {
281 switch (expression->opcode) {
293 analyze_expression (expression->inst_left, result);
303 case OP_VOIDCALL_REG:
313 case OP_VOIDCALLVIRT:
330 case OP_ICOMPARE_IMM:
334 if ( (expression->type == STACK_I4) ||
335 (expression->type == STACK_I8) ||
336 (expression->type == STACK_R8) ) {
337 if (mono_burg_arity [expression->opcode] > 0) {
338 analyze_argument (expression->inst_left, &(result->left_argument));
339 if (result->left_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY) {
340 if (mono_burg_arity [expression->opcode] > 1) {
341 analyze_argument (expression->inst_right, &(result->right_argument));
342 if (result->right_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY) {
343 result->opcode = expression->opcode;
348 result->right_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT;
349 result->opcode = expression->opcode;
364 * Given an expression description, if any of its arguments has type
365 * MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE it transforms it to a
366 * MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE, converting the
367 * variable index to its "original" one.
368 * The resulting description is OK for a "MonoSsapreExpression" (the
369 * initial description came from a "MonoSsapreExpressionOccurrence").
372 convert_ssa_variables_to_original_names (MonoSsapreExpressionDescription *result, MonoSsapreExpressionDescription *expression, MonoCompile *cfg) {
373 gssize original_variable;
375 result->opcode = expression->opcode;
376 if (expression->left_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE) {
377 result->left_argument = expression->left_argument;
379 result->left_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE;
380 original_variable = cfg->vars [expression->left_argument.argument.ssa_variable]->reg;
381 if (original_variable >= 0) {
382 result->left_argument.argument.original_variable = original_variable;
384 result->left_argument.argument.original_variable = expression->left_argument.argument.ssa_variable;
387 if (expression->right_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE) {
388 result->right_argument = expression->right_argument;
390 result->right_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE;
391 original_variable = cfg->vars [expression->right_argument.argument.ssa_variable]->reg;
392 if (original_variable >= 0) {
393 result->right_argument.argument.original_variable = original_variable;
395 result->right_argument.argument.original_variable = expression->right_argument.argument.ssa_variable;
401 * Given a MonoInst, checks if it is a phi definition.
404 is_phi_definition (MonoInst *definition) {
405 if (definition != NULL) {
406 switch (definition->opcode) {
415 if ((definition->inst_left->opcode == OP_LOCAL) &&
416 (definition->inst_right->opcode == OP_PHI)) {
430 * Given a variable index, checks if it is a phi definition
431 * (it assumes the "area" is visible).
433 #define IS_PHI_DEFINITION(v) is_phi_definition (area->cfg->vars [v]->def)
436 * Given a variable index, checks if it is a phi definition.
437 * If it is so, it returns the array of integers pointed to by the phi MonoInst
438 * (the one containing the length and the phi arguments), otherwise returns NULL.
441 get_phi_definition (MonoCompile *cfg, gssize variable) {
442 MonoInst *definition = cfg->vars [variable]->def;
443 if (is_phi_definition (definition) && (definition->inst_left->inst_c0 == variable)) {
444 return definition->inst_right->inst_phi_args;
451 * Given a variable index, returns the BB where the variable is defined.
452 * If the variable appears to have no definition, it returns the entry BB
453 * (the logic is that if it has no definition it is an argument, or a sort
454 * of constant, and in both cases it is defined in the entry BB).
456 static MonoSsapreBBInfo*
457 get_bb_info_of_definition (MonoSsapreWorkArea *area, gssize variable) {
458 MonoBasicBlock *def_bb = area->cfg->vars [variable]->def_bb;
459 if (def_bb != NULL) {
460 return area->bb_infos_in_cfg_dfn_order [def_bb->dfn];
462 return area->bb_infos;
468 * - a variable index,
469 * - a BB (the "current" BB), and
470 * - a "phi argument index" (or index in the "in_bb" of the current BB),
471 * it checks if the variable is a phi.
472 * If it is so, it returns the variable index at the in_bb corresponding to
473 * the given index, otherwise it return the variable index unchanged.
474 * The logic is to return the variable version at the given predecessor BB.
477 get_variable_version_at_predecessor_bb (MonoSsapreWorkArea *area, gssize variable, MonoSsapreBBInfo *current_bb, int phi_operand) {
478 MonoSsapreBBInfo *definition_bb = get_bb_info_of_definition (area, variable);
479 int *phi_definition = get_phi_definition (area->cfg, variable);
480 if ((definition_bb == current_bb) && (phi_definition != NULL)) {
481 return phi_definition [phi_operand + 1];
488 * Adds an expression to an autobalancing binary tree of expressions.
489 * Returns the new tree root (it can be different from "tree" because of the
492 static MonoSsapreExpression*
493 add_expression_to_tree (MonoSsapreExpression *tree, MonoSsapreExpression *expression) {
494 MonoSsapreExpression *subtree;
495 MonoSsapreExpression **subtree_reference;
497 gssize max_tree_depth, max_subtree_size;
500 expression->previous = NULL;
501 expression->next = NULL;
502 expression->tree_size = 1;
508 comparison = MONO_COMPARE_SSAPRE_EXPRESSION_DESCRIPTIONS (expression->description, tree->description);
509 if (comparison > 0) {
510 if (tree->next != NULL) {
511 subtree = tree->next;
512 subtree_reference = &(tree->next);
514 tree->next = expression;
515 expression->father = tree;
516 expression->previous = NULL;
517 expression->next = NULL;
518 expression->tree_size = 1;
521 } else if (comparison < 0) {
522 if (tree->previous != NULL) {
523 subtree = tree->previous;
524 subtree_reference = &(tree->previous);
526 tree->previous = expression;
527 expression->father = tree;
528 expression->previous = NULL;
529 expression->next = NULL;
530 expression->tree_size = 1;
534 g_assert_not_reached ();
538 MONO_SSAPRE_MAX_TREE_DEPTH (tree->tree_size, max_tree_depth);
539 max_subtree_size = (1 << max_tree_depth) -1;
541 if (subtree->tree_size < max_subtree_size) {
542 *subtree_reference = add_expression_to_tree (subtree, expression);
543 (*subtree_reference)->father = tree;
546 MonoSsapreExpression *other_subtree;
547 MonoSsapreExpression *border_expression;
548 MonoSsapreExpression *border_expression_subtree;
549 MonoSsapreExpression **border_expression_reference_from_father;
550 int comparison_with_border;
552 border_expression = subtree;
553 if (comparison > 0) {
554 other_subtree = tree->previous;
555 MONO_SSAPRE_GOTO_FIRST_EXPRESSION (border_expression);
556 border_expression_subtree = border_expression->next;
557 border_expression_reference_from_father = &(border_expression->father->previous);
558 } else if (comparison < 0) {
559 other_subtree = tree->next;
560 MONO_SSAPRE_GOTO_LAST_EXPRESSION (border_expression);
561 border_expression_subtree = border_expression->previous;
562 border_expression_reference_from_father = &(border_expression->father->next);
564 g_assert_not_reached ();
567 comparison_with_border = MONO_COMPARE_SSAPRE_EXPRESSION_DESCRIPTIONS (expression->description, border_expression->description);
569 if ((comparison + comparison_with_border) != 0) {
570 MonoSsapreExpression *border_expression_iterator = border_expression->father;
571 while (border_expression_iterator != tree) {
572 border_expression_iterator->tree_size--;
573 border_expression_iterator = border_expression_iterator->father;
576 if (border_expression != subtree) {
577 *border_expression_reference_from_father = border_expression_subtree;
579 subtree = border_expression_subtree;
581 if (border_expression_subtree != NULL) {
582 border_expression_subtree->father = border_expression->father;
585 if (comparison > 0) {
586 border_expression->previous = add_expression_to_tree (other_subtree, tree);
587 border_expression->next = add_expression_to_tree (subtree, expression);
588 } else if (comparison < 0) {
589 border_expression->previous = add_expression_to_tree (subtree, expression);
590 border_expression->next = add_expression_to_tree (other_subtree, tree);
592 g_assert_not_reached ();
595 border_expression->tree_size = 1 + border_expression->previous->tree_size + border_expression->next->tree_size;
596 return border_expression;
598 if (comparison > 0) {
599 expression->previous = add_expression_to_tree (other_subtree, tree);
600 expression->next = subtree;
601 } else if (comparison < 0) {
602 expression->previous = subtree;
603 expression->next = add_expression_to_tree (other_subtree, tree);
605 g_assert_not_reached ();
608 expression->tree_size = 1 + expression->previous->tree_size + expression->next->tree_size;
615 * Adds an expression to the worklist (putting the given occurrence as first
616 * occurrence of this expression).
619 add_expression_to_worklist (MonoSsapreWorkArea *area, MonoSsapreExpressionOccurrence *occurrence) {
620 MonoSsapreExpression *expression;
622 expression = (MonoSsapreExpression*) mono_mempool_alloc (area->mempool, sizeof (MonoSsapreExpression));
624 convert_ssa_variables_to_original_names (&(expression->description), &(occurrence->description), area->cfg);
625 expression->type = mono_type_from_stack_type (occurrence->occurrence);
626 expression->occurrences = NULL;
627 expression->last_occurrence = NULL;
628 MONO_SSAPRE_ADD_EXPRESSION_OCCURRANCE (expression, occurrence);
630 area->worklist = add_expression_to_tree (area->worklist, expression);
631 area->worklist->father = NULL;
635 * Adds an expression occurrence to the worklist.
636 * If its expression is not yet in the worklist, it is created.
639 add_occurrence_to_worklist (MonoSsapreWorkArea *area, MonoSsapreExpressionOccurrence *occurrence) {
640 MonoSsapreExpressionDescription description;
641 MonoSsapreExpression *current_expression;
644 convert_ssa_variables_to_original_names (&description, &(occurrence->description), area->cfg);
645 current_expression = area->worklist;
648 if (current_expression != NULL) {
649 comparison = MONO_COMPARE_SSAPRE_EXPRESSION_DESCRIPTIONS (description, current_expression->description);
651 if (comparison > 0) {
652 current_expression = current_expression->next;
653 } else if (comparison < 0) {
654 current_expression = current_expression->previous;
656 MONO_SSAPRE_ADD_EXPRESSION_OCCURRANCE (current_expression, occurrence);
659 add_expression_to_worklist (area, occurrence);
662 } while (comparison != 0);
666 * Process a MonoInst, and of it is a valid expression add it to the worklist.
668 static MonoSsapreExpressionOccurrence*
669 process_inst (MonoSsapreWorkArea *area, MonoInst* inst, MonoInst* previous_inst, MonoSsapreBBInfo *bb_info, MonoSsapreExpressionOccurrence *current_occurrence) {
671 /* Ugly hack to fix missing variable definitions */
672 /* (the SSA construction code should have done it already!) */
673 switch (inst->opcode) {
682 if ((inst->inst_left->opcode == OP_LOCAL) || (inst->inst_left->opcode == OP_ARG)) {
683 int variable_index = inst->inst_left->inst_c0;
685 if (area->cfg->vars [variable_index]->def_bb == NULL) {
686 if (area->cfg->verbose_level >= 4) {
687 printf ("SSAPRE WARNING: variable %d has no definition, fixing.\n", variable_index);
689 area->cfg->vars [variable_index]->def_bb = bb_info->bb;
697 if (mono_burg_arity [inst->opcode] > 0) {
698 current_occurrence = process_inst (area, inst->inst_left, previous_inst, bb_info, current_occurrence);
699 if (mono_burg_arity [inst->opcode] > 1) {
700 current_occurrence = process_inst (area, inst->inst_right, previous_inst, bb_info, current_occurrence);
704 analyze_expression (inst, &(current_occurrence->description));
705 if (current_occurrence->description.opcode != 0) {
706 current_occurrence->occurrence = inst;
707 current_occurrence->previous_tree = previous_inst;
708 current_occurrence->bb_info = bb_info;
709 current_occurrence->is_first_in_bb = FALSE;
710 current_occurrence->is_last_in_bb = FALSE;
711 add_occurrence_to_worklist (area, current_occurrence);
712 current_occurrence = (MonoSsapreExpressionOccurrence*) mono_mempool_alloc (area->mempool, sizeof (MonoSsapreExpressionOccurrence));
715 return current_occurrence;
719 * Process a BB, and (recursively) all its children in the dominator tree.
720 * The result is that all the expressions end up in the worklist, and the
721 * auxiliary MonoSsapreBBInfo fields (dt_dfn, dt_descendants) are initialized
722 * (with all the info that comes from the MonoBasicBlock).
724 static MonoSsapreExpressionOccurrence*
725 process_bb (MonoSsapreWorkArea *area, MonoBasicBlock *bb, int *dt_dfn, int *upper_descendants, MonoSsapreExpressionOccurrence *current_occurrence) {
726 MonoSsapreBBInfo *bb_info;
729 MonoInst* current_inst;
730 MonoInst* previous_inst;
732 bb_info = &(area->bb_infos [*dt_dfn]);
733 bb_info->dt_dfn = *dt_dfn;
735 bb_info->cfg_dfn = bb->dfn;
736 area->bb_infos_in_cfg_dfn_order [bb->dfn] = bb_info;
737 bb_info->in_count = bb->in_count;
738 bb_info->out_count = bb->out_count;
739 bb_info->dfrontier = bb->dfrontier;
741 bb_info->in_bb = (MonoSsapreBBInfo**) mono_mempool_alloc (area->mempool, sizeof (MonoSsapreBBInfo*) * (bb->in_count));
742 bb_info->out_bb = (MonoSsapreBBInfo**) mono_mempool_alloc (area->mempool, sizeof (MonoSsapreBBInfo*) * (bb->out_count));
743 bb_info->phi_arguments_classes = (gssize*) mono_mempool_alloc (area->mempool, sizeof (gssize) * (bb->in_count));
745 bb_info->phi_insertion_point = NULL;
747 current_inst = bb->code;
748 previous_inst = NULL;
749 while (current_inst != NULL) {
750 if (is_phi_definition (current_inst)) {
751 bb_info->phi_insertion_point = current_inst;
753 current_occurrence = process_inst (area, current_inst, previous_inst, bb_info, current_occurrence);
754 previous_inst = current_inst;
755 current_inst = current_inst->next;
759 for (dominated_bb = g_list_first (bb->dominated); dominated_bb != NULL; dominated_bb = g_list_next (dominated_bb)) {
760 current_occurrence = process_bb (area, (MonoBasicBlock*) (dominated_bb->data), dt_dfn, &descendants, current_occurrence);
762 bb_info->dt_descendants = descendants;
763 *upper_descendants += (descendants + 1);
765 return current_occurrence;
769 * Reset the MonoSsapreBBInfo fields that must be recomputed for each expression.
772 clean_bb_infos (MonoSsapreWorkArea *area) {
774 for (i = 0; i < area->num_bblocks; i++) {
775 MonoSsapreBBInfo *bb_info = &(area->bb_infos [i]);
776 bb_info->has_phi = FALSE;
777 bb_info->phi_defines_a_real_occurrence = FALSE;
778 bb_info->phi_is_down_safe = FALSE;
779 bb_info->phi_can_be_available = FALSE;
780 bb_info->phi_is_later = FALSE;
781 bb_info->phi_redundancy_class = BOTTOM_REDUNDANCY_CLASS;
782 bb_info->phi_variable_index = BOTTOM_REDUNDANCY_CLASS;
783 bb_info->has_phi_argument = FALSE;
784 bb_info->phi_argument_has_real_use = FALSE;
785 bb_info->phi_argument_needs_insert = FALSE;
786 bb_info->phi_argument_has_been_processed = FALSE;
787 bb_info->phi_argument_class = BOTTOM_REDUNDANCY_CLASS;
788 bb_info->phi_argument_variable_index = BOTTOM_REDUNDANCY_CLASS;
789 bb_info->phi_argument_defined_by_real_occurrence = NULL;
790 bb_info->phi_argument_defined_by_phi = NULL;
791 bb_info->phi_argument_left_argument_version = BOTTOM_REDUNDANCY_CLASS;
792 bb_info->phi_argument_right_argument_version = BOTTOM_REDUNDANCY_CLASS;
793 bb_info->first_expression_in_bb = NULL;
794 bb_info->next_interesting_bb = NULL;
795 bb_info->next_in_renaming_stack = NULL;
796 bb_info->top_of_local_renaming_stack = NULL;
801 * Reset the MonoSsapreWorkArea fields that must be recomputed for each expression.
804 clean_area_infos (MonoSsapreWorkArea *area) {
805 mono_bitset_clear_all (area->left_argument_bb_bitset);
806 mono_bitset_clear_all (area->right_argument_bb_bitset);
807 area->num_vars = area->cfg->num_varinfo;
808 area->top_of_renaming_stack = NULL;
809 area->bb_on_top_of_renaming_stack = NULL;
810 area->first_interesting_bb = NULL;
811 area->saved_occurrences = 0;
812 area->reloaded_occurrences = 0;
813 area->inserted_occurrences = 0;
814 area->unaltered_occurrences = 0;
815 area->added_phis = 0;
816 clean_bb_infos (area);
820 * Utility function to combine the dominance frontiers of a set of BBs.
823 compute_combined_dfrontier (MonoSsapreWorkArea *area, MonoBitSet* result, MonoBitSet *bblocks)
826 mono_bitset_clear_all (result);
827 mono_bitset_foreach_bit (bblocks, i, area->num_bblocks) {
828 mono_bitset_union (result, area->bb_infos_in_cfg_dfn_order [i]->dfrontier);
833 * Utility function to compute the combined dominance frontier of a set of BBs.
836 compute_combined_iterated_dfrontier (MonoSsapreWorkArea *area, MonoBitSet *result, MonoBitSet *bblocks, MonoBitSet *buffer)
838 gboolean change = TRUE;
840 compute_combined_dfrontier (area, result, bblocks);
843 compute_combined_dfrontier (area, buffer, result);
844 mono_bitset_union (buffer, result);
846 if (!mono_bitset_equal (buffer, result)) {
847 mono_bitset_copyto (buffer, result);
854 * See paper, figure 18, function Set_var_phis
856 static void process_phi_variable_in_phi_insertion (MonoSsapreWorkArea *area, gssize variable, MonoBitSet *phi_bbs) {
857 int* phi_definition = get_phi_definition (area->cfg, variable);
859 if (phi_definition != NULL) {
860 int definition_bb = area->cfg->vars [variable]->def_bb->dfn;
861 if (! mono_bitset_test (phi_bbs, definition_bb)) {
863 mono_bitset_set (phi_bbs, definition_bb);
864 for (i = 0; i < *phi_definition; i++) {
865 process_phi_variable_in_phi_insertion (area, phi_definition [i+1], phi_bbs);
872 * See paper, figure 18, function phi_insertion
875 phi_insertion (MonoSsapreWorkArea *area, MonoSsapreExpression *expression) {
876 MonoSsapreExpressionOccurrence *current_expression = NULL;
877 MonoSsapreExpressionOccurrence *previous_expression = NULL;
878 MonoSsapreBBInfo *current_bb = NULL;
879 MonoSsapreBBInfo *previous_interesting_bb = NULL;
880 int i, j, current_bb_dt_dfn;
882 mono_bitset_clear_all (area->expression_occurrences_buffer);
883 for (current_expression = expression->occurrences; current_expression != NULL; current_expression = current_expression->next) {
884 mono_bitset_set (area->expression_occurrences_buffer, current_expression->bb_info->cfg_dfn);
885 if (current_expression->description.left_argument.type == MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE) {
886 process_phi_variable_in_phi_insertion (area, current_expression->description.left_argument.argument.ssa_variable, area->left_argument_bb_bitset);
888 if (current_expression->description.right_argument.type == MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE) {
889 process_phi_variable_in_phi_insertion (area, current_expression->description.right_argument.argument.ssa_variable, area->right_argument_bb_bitset);
892 if (previous_expression != NULL) {
893 if (previous_expression->bb_info != current_expression->bb_info) {
894 previous_expression->is_last_in_bb = TRUE;
895 current_expression->is_first_in_bb = TRUE;
896 current_expression->bb_info->first_expression_in_bb = current_expression;
899 current_expression->is_first_in_bb = TRUE;
900 current_expression->bb_info->first_expression_in_bb = current_expression;
903 previous_expression = current_expression;
905 previous_expression->is_last_in_bb = TRUE;
907 compute_combined_iterated_dfrontier (area, area->iterated_dfrontier_buffer, area->expression_occurrences_buffer, area->bb_iteration_buffer);
909 mono_bitset_union (area->iterated_dfrontier_buffer, area->left_argument_bb_bitset);
910 mono_bitset_union (area->iterated_dfrontier_buffer, area->right_argument_bb_bitset);
912 mono_bitset_foreach_bit (area->iterated_dfrontier_buffer, i, area->num_bblocks) {
913 area->bb_infos_in_cfg_dfn_order [i]->has_phi = TRUE;
914 area->bb_infos_in_cfg_dfn_order [i]->phi_can_be_available = TRUE;
915 for (j = 0; j < area->bb_infos_in_cfg_dfn_order [i]->in_count; j++) {
916 area->bb_infos_in_cfg_dfn_order [i]->in_bb [j]->has_phi_argument = TRUE;
920 for (current_bb = area->bb_infos, current_bb_dt_dfn = 0; current_bb_dt_dfn < area->num_bblocks; current_bb++, current_bb_dt_dfn++) {
921 if ((current_bb->first_expression_in_bb != NULL) || (current_bb->has_phi) || (current_bb->has_phi_argument)) {
922 if (previous_interesting_bb != NULL) {
923 previous_interesting_bb->next_interesting_bb = current_bb;
925 area->first_interesting_bb = current_bb;
927 previous_interesting_bb = current_bb;
933 * Macro that pushes a real occurrence on the stack
935 #define PUSH_REAL_OCCURRENCE(o) do{\
936 if (area->bb_on_top_of_renaming_stack != (o)->bb_info) { \
937 (o)->bb_info->next_in_renaming_stack = area->bb_on_top_of_renaming_stack; \
938 area->bb_on_top_of_renaming_stack =(o)->bb_info; \
939 (o)->next_in_renaming_stack = NULL; \
941 (o)->next_in_renaming_stack = area->top_of_renaming_stack; \
943 (o)->bb_info->top_of_local_renaming_stack = (o); \
944 area->top_of_renaming_stack = (o); \
945 area->bb_on_top_of_renaming_stack->phi_argument_has_real_use = FALSE; \
949 * Macro that pushes a PHI occurrence on the stack
951 #define PUSH_PHI_OCCURRENCE(b) do{\
952 if (area->bb_on_top_of_renaming_stack != (b)) { \
953 (b)->next_in_renaming_stack = area->bb_on_top_of_renaming_stack; \
954 area->bb_on_top_of_renaming_stack = (b); \
956 (b)->top_of_local_renaming_stack = NULL; \
957 area->top_of_renaming_stack = NULL; \
958 area->bb_on_top_of_renaming_stack->phi_argument_has_real_use = FALSE; \
962 * See paper, section 5.1, definition of "Dominate"
965 dominates (MonoSsapreBBInfo *dominator, MonoSsapreBBInfo *dominated) {
966 if ((dominator->dt_dfn <= dominated->dt_dfn) && (dominated->dt_dfn <= (dominator->dt_dfn + dominator->dt_descendants))) {
974 * See paper, section 5.4.
975 * The two passes are coded sequentially (no separate "rename1" and "rename2" functions).
978 renaming_pass (MonoSsapreWorkArea *area) {
979 MonoSsapreBBInfo *current_bb = NULL;
980 MonoSsapreBBInfo *previous_bb = NULL;
981 MonoSsapreExpressionOccurrence *current_expression = NULL;
982 gssize current_class = 0;
984 /* This loop is "rename1" */
985 for (current_bb = area->first_interesting_bb, previous_bb = NULL; current_bb != NULL; previous_bb = current_bb, current_bb = current_bb->next_interesting_bb) {
986 if ((previous_bb != NULL) && ! dominates (previous_bb, current_bb)) {
987 if ((area->bb_on_top_of_renaming_stack != NULL) && (area->top_of_renaming_stack == NULL) && (previous_bb->phi_argument_has_real_use == FALSE)) {
989 printf ("Clearing down safe in PHI %d because of backtracking (previous block is [bb %d [ID %d]])\n",
990 area->bb_on_top_of_renaming_stack->phi_redundancy_class, previous_bb->cfg_dfn, previous_bb->bb->block_num);
992 area->bb_on_top_of_renaming_stack->phi_is_down_safe = FALSE;
994 while ((area->bb_on_top_of_renaming_stack != NULL) && ! dominates (area->bb_on_top_of_renaming_stack, current_bb)) {
995 MonoSsapreBBInfo *top_bb = area->bb_on_top_of_renaming_stack;
996 if (top_bb->next_in_renaming_stack != NULL) {
997 area->top_of_renaming_stack = top_bb->next_in_renaming_stack->top_of_local_renaming_stack;
999 area->top_of_renaming_stack = NULL;
1001 area->bb_on_top_of_renaming_stack = top_bb->next_in_renaming_stack;
1004 if (current_bb->idominator != NULL) {
1005 current_bb->phi_argument_has_real_use = current_bb->idominator->phi_argument_has_real_use;
1007 current_bb->phi_argument_has_real_use = FALSE;
1010 if (current_bb->has_phi) {
1011 current_bb->phi_is_down_safe = TRUE;
1012 current_bb->phi_redundancy_class = current_class;
1014 PUSH_PHI_OCCURRENCE (current_bb);
1017 for (current_expression = current_bb->first_expression_in_bb; (current_expression != NULL) && (current_expression->bb_info == current_bb); current_expression = current_expression->next) {
1018 if (area->top_of_renaming_stack != NULL) {
1019 MonoSsapreExpressionOccurrence *top = area->top_of_renaming_stack;
1021 if (((current_expression->description.left_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE) ||
1022 (current_expression->description.left_argument.argument.ssa_variable == top->description.left_argument.argument.ssa_variable)) &&
1023 ((current_expression->description.right_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE) ||
1024 (current_expression->description.right_argument.argument.ssa_variable == top->description.right_argument.argument.ssa_variable))) {
1025 current_expression->redundancy_class = top->redundancy_class;
1026 current_expression->defined_by_real_occurrence = top;
1028 current_expression->redundancy_class = current_class;
1030 current_expression->defined_by_real_occurrence = NULL;
1031 PUSH_REAL_OCCURRENCE (current_expression);
1033 current_expression->defined_by_phi = NULL;
1034 } else if (area->bb_on_top_of_renaming_stack != NULL) {
1035 MonoSsapreBBInfo *phi_bb = area->bb_on_top_of_renaming_stack;
1036 gssize left_argument_version = ((current_expression->description.left_argument.type == MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE)?
1037 (current_expression->description.left_argument.argument.ssa_variable):BOTTOM_REDUNDANCY_CLASS);
1038 gssize right_argument_version = ((current_expression->description.right_argument.type == MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE)?
1039 (current_expression->description.right_argument.argument.ssa_variable):BOTTOM_REDUNDANCY_CLASS);
1041 /* See remark in section 5.4 about the dominance relation between PHI */
1042 /* occurrences and phi definitions */
1043 MonoSsapreBBInfo *left_argument_definition_bb = ((left_argument_version != BOTTOM_REDUNDANCY_CLASS)?
1044 (get_bb_info_of_definition (area, left_argument_version)):NULL);
1045 MonoSsapreBBInfo *right_argument_definition_bb = ((right_argument_version != BOTTOM_REDUNDANCY_CLASS)?
1046 (get_bb_info_of_definition (area, right_argument_version)):NULL);
1048 gboolean left_same_class_condition = ((left_argument_definition_bb == NULL) || ((left_argument_definition_bb != phi_bb) ? dominates (left_argument_definition_bb, phi_bb) :
1049 (IS_PHI_DEFINITION (left_argument_version) ? TRUE : FALSE)));
1050 gboolean right_same_class_condition = ((right_argument_definition_bb == NULL) || ((right_argument_definition_bb != phi_bb) ? dominates (right_argument_definition_bb, phi_bb) :
1051 (IS_PHI_DEFINITION (right_argument_version) ? TRUE : FALSE)));
1053 if (left_same_class_condition && right_same_class_condition) {
1056 phi_bb->phi_defines_a_real_occurrence = TRUE;
1057 current_bb->phi_argument_has_real_use = TRUE;
1058 current_expression->redundancy_class = phi_bb->phi_redundancy_class;
1059 current_expression->defined_by_phi = phi_bb;
1062 * Major difference from the paper here...
1063 * Instead of maintaining "set_for_rename2" (see figure 20), we just
1064 * compute "phi_argument_left_argument_version" (and right) here, and
1065 * use that in rename2, saving us the hassle of maintaining a set
1066 * data structure (and the related allocations).
1068 for (phi_argument = 0; phi_argument < phi_bb->in_count; phi_argument++) {
1069 MonoSsapreBBInfo *previous_bb = phi_bb->in_bb [phi_argument];
1070 if (left_argument_version != BOTTOM_REDUNDANCY_CLASS) {
1071 previous_bb->phi_argument_left_argument_version = get_variable_version_at_predecessor_bb (area,
1072 left_argument_version, phi_bb, phi_argument);
1074 if (right_argument_version != BOTTOM_REDUNDANCY_CLASS) {
1075 previous_bb->phi_argument_right_argument_version = get_variable_version_at_predecessor_bb (area,
1076 right_argument_version, phi_bb, phi_argument);
1080 current_expression->redundancy_class = current_class;
1082 current_expression->defined_by_phi = NULL;
1083 PUSH_REAL_OCCURRENCE (current_expression);
1084 phi_bb->phi_is_down_safe = FALSE;
1086 printf ("Clearing down safe in PHI %d because of real occurrence %d\n",
1087 phi_bb->phi_redundancy_class, current_expression->redundancy_class);
1090 current_expression->defined_by_real_occurrence = NULL;
1092 current_expression->redundancy_class = current_class;
1094 current_expression->defined_by_real_occurrence = NULL;
1095 current_expression->defined_by_phi = NULL;
1096 PUSH_REAL_OCCURRENCE (current_expression);
1100 if (current_bb->has_phi_argument) {
1101 if (area->top_of_renaming_stack != NULL) {
1102 current_bb->phi_argument_defined_by_real_occurrence = area->top_of_renaming_stack;
1103 current_bb->phi_argument_class = area->top_of_renaming_stack->redundancy_class;
1104 } else if (area->bb_on_top_of_renaming_stack != NULL) {
1105 current_bb->phi_argument_defined_by_phi = area->bb_on_top_of_renaming_stack;
1106 current_bb->phi_argument_class = area->bb_on_top_of_renaming_stack->phi_redundancy_class;
1108 current_bb->phi_argument_class = BOTTOM_REDUNDANCY_CLASS;
1112 if ((area->bb_on_top_of_renaming_stack != NULL) && (area->top_of_renaming_stack == NULL) && (previous_bb->phi_argument_has_real_use == FALSE)) {
1114 printf ("Clearing down safe in PHI %d because of backtracking (previous block is [bb %d [ID %d]])\n",
1115 area->bb_on_top_of_renaming_stack->phi_redundancy_class, previous_bb->cfg_dfn, previous_bb->bb->block_num);
1117 area->bb_on_top_of_renaming_stack->phi_is_down_safe = FALSE;
1119 area->number_of_classes = current_class;
1121 /* This loop is "rename2" */
1122 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
1123 if (current_bb->has_phi_argument) {
1124 if ((current_bb->phi_argument_left_argument_version != BOTTOM_REDUNDANCY_CLASS) || (current_bb->phi_argument_right_argument_version != BOTTOM_REDUNDANCY_CLASS)) {
1125 if (current_bb->phi_argument_defined_by_real_occurrence != NULL) {
1126 if (((current_bb->phi_argument_left_argument_version != BOTTOM_REDUNDANCY_CLASS) &&
1127 (current_bb->phi_argument_left_argument_version != current_bb->phi_argument_defined_by_real_occurrence->description.left_argument.argument.ssa_variable)) ||
1128 ((current_bb->phi_argument_right_argument_version != BOTTOM_REDUNDANCY_CLASS) &&
1129 (current_bb->phi_argument_right_argument_version != current_bb->phi_argument_defined_by_real_occurrence->description.right_argument.argument.ssa_variable))) {
1130 current_bb->phi_argument_class = BOTTOM_REDUNDANCY_CLASS;
1132 } else if (current_bb->phi_argument_defined_by_phi != NULL) {
1133 MonoSsapreBBInfo *phi_bb = current_bb->phi_argument_defined_by_phi;
1134 MonoSsapreBBInfo *left_argument_definition_bb = (current_bb->phi_argument_left_argument_version != BOTTOM_REDUNDANCY_CLASS) ?
1135 get_bb_info_of_definition (area, current_bb->phi_argument_left_argument_version) : NULL;
1136 MonoSsapreBBInfo *right_argument_definition_bb = (current_bb->phi_argument_right_argument_version != BOTTOM_REDUNDANCY_CLASS) ?
1137 get_bb_info_of_definition (area, current_bb->phi_argument_right_argument_version) : NULL;
1138 /* See remark in section 5.4 about the dominance relation between PHI */
1139 /* occurrences and phi definitions */
1140 gboolean left_bottom_condition = ((left_argument_definition_bb != NULL) && ! ((left_argument_definition_bb != phi_bb) ? dominates (left_argument_definition_bb, phi_bb) :
1141 (IS_PHI_DEFINITION (current_bb->phi_argument_left_argument_version) ? TRUE : FALSE)));
1142 gboolean right_bottom_condition = ((right_argument_definition_bb != NULL) && ! ((right_argument_definition_bb != phi_bb) ? dominates (right_argument_definition_bb, phi_bb) :
1143 (IS_PHI_DEFINITION (current_bb->phi_argument_right_argument_version) ? TRUE : FALSE)));
1145 if (left_bottom_condition || right_bottom_condition) {
1146 current_bb->phi_argument_class = BOTTOM_REDUNDANCY_CLASS;
1149 current_bb->phi_argument_class = BOTTOM_REDUNDANCY_CLASS;
1152 current_bb->phi_argument_class = BOTTOM_REDUNDANCY_CLASS;
1155 if (current_bb->phi_argument_class == BOTTOM_REDUNDANCY_CLASS) {
1156 if ((current_bb->phi_argument_defined_by_phi != NULL) && (! current_bb->phi_argument_has_real_use)) {
1158 printf ("Clearing down safe in PHI %d because PHI argument in block [bb %d [ID %d]] is BOTTOM\n",
1159 current_bb->phi_argument_defined_by_phi->phi_redundancy_class, current_bb->cfg_dfn, current_bb->bb->block_num);
1161 current_bb->phi_argument_defined_by_phi->phi_is_down_safe = FALSE;
1163 current_bb->phi_argument_has_real_use = FALSE;
1168 /* Final quick pass to copy the result of "rename2" into PHI nodes */
1169 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
1170 if (current_bb->has_phi) {
1172 for (i = 0; i < current_bb->in_count; i++) {
1173 current_bb->phi_arguments_classes [i] = current_bb->in_bb [i]->phi_argument_class;
1179 #undef PUSH_REAL_OCCURRENCE
1180 #undef PUSH_PHI_OCCURRENCE
1183 * See paper, figure 8
1186 reset_down_safe (MonoSsapreBBInfo *phi_argument) {
1187 if ((phi_argument->phi_argument_class != BOTTOM_REDUNDANCY_CLASS) && (! phi_argument->phi_argument_has_real_use) && (phi_argument->phi_argument_defined_by_phi != NULL) && (phi_argument->phi_argument_defined_by_phi->phi_is_down_safe)) {
1189 MonoSsapreBBInfo *phi = phi_argument->phi_argument_defined_by_phi;
1190 // if (TRACE_SSAPRE) {
1191 // printf ("Clearing down safe in PHI %d inside reset_down_safe\n", phi->phi_redundancy_class);
1193 phi->phi_is_down_safe = FALSE;
1194 for (i = 0; i < phi->in_count; i++) {
1195 reset_down_safe (phi->in_bb [i]);
1201 * See paper, figure 8
1204 down_safety (MonoSsapreWorkArea *area) {
1205 MonoSsapreBBInfo *current_bb = NULL;
1207 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
1208 if (current_bb->has_phi) {
1209 if (! current_bb->phi_is_down_safe) {
1211 for (i = 0; i < current_bb->in_count; i++) {
1212 reset_down_safe (current_bb->in_bb [i]);
1220 * See paper, figure 10
1223 reset_can_be_available (MonoSsapreWorkArea *area, MonoSsapreBBInfo *phi) {
1224 MonoSsapreBBInfo *current_bb = NULL;
1226 phi->phi_can_be_available = FALSE;
1227 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
1228 if (current_bb->has_phi) {
1229 gboolean phi_is_interesting = FALSE;
1232 for (i = 0; i < current_bb->in_count; i++) {
1233 MonoSsapreBBInfo *phi_argument = current_bb->in_bb [i];
1234 if ((phi_argument->phi_argument_class == current_bb->phi_redundancy_class) && (! phi_argument->phi_argument_has_real_use)) {
1235 phi_is_interesting = TRUE;
1240 if (phi_is_interesting && (! current_bb->phi_is_down_safe) && (current_bb->phi_can_be_available)) {
1241 reset_can_be_available (area, current_bb);
1248 * See paper, figure 10
1251 compute_can_be_available (MonoSsapreWorkArea *area) {
1252 MonoSsapreBBInfo *current_bb = NULL;
1254 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
1255 if (current_bb->has_phi) {
1256 if ((! current_bb->phi_is_down_safe) && (current_bb->phi_can_be_available)) {
1257 gboolean phi_is_interesting = FALSE;
1260 for (i = 0; i < current_bb->in_count; i++) {
1261 if (current_bb->phi_arguments_classes [i] == BOTTOM_REDUNDANCY_CLASS) {
1262 phi_is_interesting = TRUE;
1267 if (phi_is_interesting) {
1268 reset_can_be_available (area, current_bb);
1276 * See paper, figure 10
1279 reset_later (MonoSsapreWorkArea *area, MonoSsapreBBInfo *phi) {
1280 MonoSsapreBBInfo *current_bb = NULL;
1282 if (phi->phi_is_later) {
1283 phi->phi_is_later = FALSE;
1284 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
1285 if (current_bb->has_phi) {
1286 gboolean phi_is_interesting = FALSE;
1289 for (i = 0; i < current_bb->in_count; i++) {
1290 MonoSsapreBBInfo *phi_argument = current_bb->in_bb [i];
1291 if (phi_argument->phi_argument_class == current_bb->phi_redundancy_class) {
1292 phi_is_interesting = TRUE;
1297 if (phi_is_interesting) {
1298 reset_later (area, current_bb);
1306 * See paper, figure 10
1309 compute_later (MonoSsapreWorkArea *area) {
1310 MonoSsapreBBInfo *current_bb = NULL;
1312 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
1313 if (current_bb->has_phi) {
1314 current_bb->phi_is_later = current_bb->phi_can_be_available;
1317 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
1318 if (current_bb->has_phi) {
1319 if (current_bb->phi_is_later) {
1320 gboolean phi_is_interesting = FALSE;
1323 for (i = 0; i < current_bb->in_count; i++) {
1324 MonoSsapreBBInfo *phi_argument = current_bb->in_bb [i];
1325 if ((phi_argument->phi_argument_class != BOTTOM_REDUNDANCY_CLASS) && (phi_argument->phi_argument_has_real_use)) {
1326 phi_is_interesting = TRUE;
1331 if (phi_is_interesting) {
1332 reset_later (area, current_bb);
1340 * See paper, figure 12, function Finalize_1
1342 static void finalize_availability_and_reload (MonoSsapreWorkArea *area, MonoSsapreAvailabilityTableElement *availability_table) {
1343 MonoSsapreBBInfo *current_bb = NULL;
1344 MonoSsapreExpressionOccurrence *current_expression = NULL;
1346 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
1347 if (current_bb->has_phi) {
1348 if (current_bb->phi_can_be_available && ! current_bb->phi_is_later) {
1349 availability_table [current_bb->phi_redundancy_class].class_defined_by_phi = current_bb;
1353 for (current_expression = current_bb->first_expression_in_bb; (current_expression != NULL) && (current_expression->bb_info == current_bb); current_expression = current_expression->next) {
1354 MonoSsapreBBInfo *defining_bb = availability_table [current_expression->redundancy_class].class_defined_by_phi;
1355 if (defining_bb == NULL && availability_table [current_expression->redundancy_class].class_defined_by_real_occurrence != NULL) {
1356 defining_bb = availability_table [current_expression->redundancy_class].class_defined_by_real_occurrence->bb_info;
1358 if (defining_bb != NULL) {
1359 if (! dominates (defining_bb, current_bb)) {
1364 if (defining_bb == NULL) {
1365 current_expression->reload = FALSE;
1366 availability_table [current_expression->redundancy_class].class_defined_by_real_occurrence = current_expression;
1368 current_expression->reload = TRUE;
1369 current_expression->defined_by_phi = availability_table [current_expression->redundancy_class].class_defined_by_phi;
1370 current_expression->defined_by_real_occurrence = availability_table [current_expression->redundancy_class].class_defined_by_real_occurrence;
1373 current_expression->save = FALSE;
1376 if (current_bb->has_phi_argument) {
1377 MonoSsapreBBInfo *phi_bb = current_bb->out_bb [0];
1378 if (((phi_bb->phi_can_be_available) && (! phi_bb->phi_is_later)) &&
1379 ((current_bb->phi_argument_class == BOTTOM_REDUNDANCY_CLASS) ||
1380 ((current_bb->phi_argument_has_real_use == FALSE) && (current_bb->phi_argument_defined_by_phi != NULL) &&
1381 (! ((current_bb->phi_argument_defined_by_phi->phi_can_be_available) && (! current_bb->phi_argument_defined_by_phi->phi_is_later)))
1383 current_bb->phi_argument_needs_insert = TRUE;
1384 current_bb->phi_argument_defined_by_real_occurrence = NULL;
1385 current_bb->phi_argument_defined_by_phi = NULL;
1387 current_bb->phi_argument_needs_insert = FALSE;
1388 if (current_bb->phi_argument_class != BOTTOM_REDUNDANCY_CLASS) {
1389 current_bb->phi_argument_defined_by_real_occurrence = availability_table [current_bb->phi_argument_class].class_defined_by_real_occurrence;
1390 current_bb->phi_argument_defined_by_phi = availability_table [current_bb->phi_argument_class].class_defined_by_phi;
1394 current_bb->phi_argument_has_been_processed = FALSE;
1400 * See paper, figure 13, function Set_save
1402 static void set_save (MonoSsapreBBInfo *phi_occurrance, MonoSsapreExpressionOccurrence *real_occurrance) {
1403 if (real_occurrance != NULL) {
1404 real_occurrance->save = TRUE;
1405 } else if (phi_occurrance != NULL) {
1407 for (i = 0; i < phi_occurrance->in_count; i++) {
1408 MonoSsapreBBInfo *phi_argument = phi_occurrance->in_bb [i];
1409 if (! phi_argument->phi_argument_has_been_processed) {
1410 phi_argument->phi_argument_has_been_processed = TRUE;
1411 set_save (phi_argument->phi_argument_defined_by_phi, phi_argument->phi_argument_defined_by_real_occurrence);
1418 * See paper, figure 13, function Finalize_2 (note that we still don't do
1419 * extraneous PHI elimination, see function Set_replacement)
1421 static void finalize_save (MonoSsapreWorkArea *area) {
1422 MonoSsapreBBInfo *current_bb = NULL;
1423 MonoSsapreExpressionOccurrence *current_expression = NULL;
1425 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
1426 for (current_expression = current_bb->first_expression_in_bb; (current_expression != NULL) && (current_expression->bb_info == current_bb); current_expression = current_expression->next) {
1427 if (current_expression->reload) {
1428 set_save (current_expression->defined_by_phi, current_expression->defined_by_real_occurrence);
1432 if ((current_bb->has_phi_argument) &&
1433 (! current_bb->phi_argument_needs_insert) &&
1434 (current_bb->phi_argument_class != BOTTOM_REDUNDANCY_CLASS) &&
1435 (current_bb->phi_argument_defined_by_real_occurrence != NULL)) {
1436 current_bb->phi_argument_defined_by_real_occurrence->save = TRUE;
1442 * Perform all "finalize" steps
1444 static void finalize (MonoSsapreWorkArea *area) {
1445 MonoSsapreAvailabilityTableElement *availability_table = alloca (sizeof (MonoSsapreAvailabilityTableElement) * (area->number_of_classes));
1448 for (i = 0; i < area->number_of_classes; i++) {
1449 availability_table[i].class_defined_by_phi = NULL;
1450 availability_table[i].class_defined_by_real_occurrence = NULL;
1453 finalize_availability_and_reload (area, availability_table);
1454 finalize_save (area);
1458 * Macros that help in creating constants
1460 #define NEW_INST(dest,op) do { \
1461 (dest) = mono_mempool_alloc0 (area->cfg->mempool, sizeof (MonoInst)); \
1462 (dest)->opcode = (op); \
1465 #define NEW_I4(dest,val) do { \
1466 NEW_INST ((dest), OP_ICONST); \
1467 (dest)->inst_c0 = (val); \
1468 (dest)->type = STACK_I4; \
1471 #define NEW_I8(dest,val) do { \
1472 NEW_INST ((dest), OP_I8CONST); \
1473 (dest)->inst_l = (val); \
1474 (dest)->type = STACK_I8; \
1477 #define NEW_R4(dest,f) do { \
1478 NEW_INST ((dest), OP_R4CONST); \
1479 (dest)->inst_p0 = f; \
1480 (dest)->type = STACK_R8; \
1483 #define NEW_R8(dest,d) do { \
1484 NEW_INST ((dest), OP_R8CONST); \
1485 (dest)->inst_p0 = d; \
1486 (dest)->type = STACK_R8; \
1490 * Create a MonoInst that represents an expression argument
1493 create_expression_argument (MonoSsapreWorkArea *area, MonoSsapreExpressionArgument *argument) {
1496 switch (argument->type) {
1497 case MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT:
1499 case MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE:
1500 return mono_compile_create_var_load (area->cfg, argument->argument.ssa_variable);
1501 case MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT:
1502 NEW_I4 (result, argument->argument.integer_constant);
1504 case MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT:
1505 NEW_I8 (result, *(argument->argument.long_constant));
1507 case MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT:
1508 NEW_R4 (result, argument->argument.float_constant);
1510 case MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT:
1511 NEW_R8 (result, argument->argument.double_constant);
1513 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE:
1514 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY:
1516 g_assert_not_reached ();
1522 * Create a MonoInst that represents an expression
1525 create_expression (MonoSsapreWorkArea *area, MonoSsapreExpressionDescription *expression) {
1527 NEW_INST (result, expression->opcode);
1528 result->inst_left = create_expression_argument (area, &(expression->left_argument));
1529 result->inst_right = create_expression_argument (area, &(expression->right_argument));
1534 * See paper, section 3.6
1536 static void code_motion (MonoSsapreWorkArea *area) {
1537 MonoSsapreBBInfo *current_bb = NULL;
1538 MonoSsapreExpressionOccurrence *current_expression = NULL;
1540 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
1541 if ((current_bb->has_phi) && (current_bb->phi_can_be_available && ! current_bb->phi_is_later)) {
1542 MonoInst *new_var = mono_compile_create_var (area->cfg, area->current_expression->type, OP_LOCAL);
1543 current_bb->phi_variable_index = new_var->inst_c0;
1545 current_bb->phi_variable_index = BOTTOM_REDUNDANCY_CLASS;
1548 for (current_expression = current_bb->first_expression_in_bb; (current_expression != NULL) && (current_expression->bb_info == current_bb); current_expression = current_expression->next) {
1549 if (current_expression->save) {
1550 MonoInst *new_var = mono_compile_create_var (area->cfg, area->current_expression->type, OP_LOCAL);
1551 current_expression->variable_index = new_var->inst_c0;
1553 current_expression->variable_index = BOTTOM_REDUNDANCY_CLASS;
1557 if ((current_bb->has_phi_argument) && (current_bb->phi_argument_needs_insert)) {
1558 MonoInst *new_var = mono_compile_create_var (area->cfg, area->current_expression->type, OP_LOCAL);
1559 current_bb->phi_argument_variable_index = new_var->inst_c0;
1561 current_bb->phi_argument_variable_index = BOTTOM_REDUNDANCY_CLASS;
1565 for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
1566 if (current_bb->phi_variable_index != BOTTOM_REDUNDANCY_CLASS) {
1571 NEW_INST (phi, OP_PHI);
1572 phi->inst_phi_args = mono_mempool_alloc (area->cfg->mempool, (sizeof (int) * ((current_bb->in_count) + 1)));
1573 phi->inst_phi_args [0] = current_bb->in_count;
1574 for (in_bb = 0; in_bb < current_bb->in_count; in_bb++) {
1575 gssize phi_argument_variable_index = current_bb->in_bb [in_bb]->phi_argument_variable_index;
1576 if (phi_argument_variable_index == BOTTOM_REDUNDANCY_CLASS) {
1577 MonoSsapreBBInfo *phi_argument_bb = current_bb->in_bb [in_bb];
1578 if (phi_argument_bb->phi_argument_defined_by_phi !=NULL) {
1579 phi_argument_variable_index = phi_argument_bb->phi_argument_defined_by_phi->phi_variable_index;
1580 } else if (phi_argument_bb->phi_argument_defined_by_real_occurrence !=NULL) {
1581 phi_argument_variable_index = phi_argument_bb->phi_argument_defined_by_real_occurrence->variable_index;
1583 g_assert_not_reached ();
1586 phi->inst_phi_args [in_bb + 1] = phi_argument_variable_index;
1588 store = mono_compile_create_var_store (area->cfg, current_bb->phi_variable_index, phi);
1589 if (current_bb->phi_insertion_point != NULL) {
1590 store->next = current_bb->phi_insertion_point->next;
1591 current_bb->phi_insertion_point->next = store;
1593 store->next = current_bb->bb->code;
1594 current_bb->bb->code = store;
1596 current_bb->phi_insertion_point = store;
1598 area->added_phis ++;
1601 for (current_expression = current_bb->first_expression_in_bb; (current_expression != NULL) && (current_expression->bb_info == current_bb); current_expression = current_expression->next) {
1602 gboolean altered = FALSE;
1603 if (current_expression->reload) {
1604 gssize variable_index;
1605 if (current_expression->defined_by_phi != NULL) {
1606 variable_index = current_expression->defined_by_phi->phi_variable_index;
1607 } else if (current_expression->defined_by_real_occurrence != NULL) {
1608 variable_index = current_expression->defined_by_real_occurrence->variable_index;
1610 variable_index = BOTTOM_REDUNDANCY_CLASS;
1611 g_assert_not_reached ();
1613 mono_compile_make_var_load (area->cfg, current_expression->occurrence, variable_index);
1615 area->reloaded_occurrences ++;
1618 if (current_expression->save) {
1620 MonoInst *moved_expression = mono_mempool_alloc (area->cfg->mempool, sizeof (MonoInst));
1621 *moved_expression = *(current_expression->occurrence);
1622 store = mono_compile_create_var_store (area->cfg, current_expression->variable_index, moved_expression);
1623 if (current_expression->previous_tree != NULL) {
1624 store->next = current_expression->previous_tree->next;
1625 current_expression->previous_tree->next = store;
1627 store->next = current_bb->bb->code;
1628 current_bb->bb->code = store;
1630 mono_compile_make_var_load (area->cfg, current_expression->occurrence, current_expression->variable_index);
1632 area->saved_occurrences ++;
1636 area->unaltered_occurrences ++;
1640 if (current_bb->phi_argument_variable_index != BOTTOM_REDUNDANCY_CLASS) {
1641 MonoSsapreExpressionDescription expression_description;
1642 MonoInst *inserted_expression;
1645 expression_description = area->current_expression->description;
1646 if (expression_description.left_argument.type == MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE) {
1647 expression_description.left_argument.argument.ssa_variable = current_bb->phi_argument_left_argument_version;
1648 expression_description.left_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE;
1650 if (expression_description.right_argument.type == MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE) {
1651 expression_description.right_argument.argument.ssa_variable = current_bb->phi_argument_right_argument_version;
1652 expression_description.right_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE;
1655 inserted_expression = create_expression (area, &expression_description);
1656 store = mono_compile_create_var_store (area->cfg, current_bb->phi_argument_variable_index, inserted_expression);
1658 mono_add_ins_to_end (current_bb->bb, store);
1660 area->inserted_occurrences ++;
1666 * Perform all SSAPRE steps for an expression
1669 process_expression (MonoSsapreWorkArea *area, MonoSsapreExpression *expression) {
1670 if (area->cfg->verbose_level >= TRACE_LEVEL) {
1671 printf ("SSAPRE STARTS PROCESSING EXPRESSION ");
1672 print_expression_description (&(expression->description));
1676 clean_area_infos (area);
1678 area->current_expression = expression;
1679 phi_insertion (area, expression);
1680 renaming_pass (area);
1682 if (area->cfg->verbose_level >= TRACE_LEVEL) {
1683 printf ("START SUMMARY OF BB INFOS\n");
1684 print_bb_infos (area);
1685 printf ("END SUMMARY OF BB INFOS\n");
1689 compute_can_be_available (area);
1690 compute_later (area);
1694 if (area->cfg->verbose_level >= DUMP_LEVEL) {
1695 printf ("START DUMP OF BB INFOS\n");
1697 printf ("END DUMP OF BB INFOS\n");
1698 } else if (area->cfg->verbose_level >= TRACE_LEVEL) {
1699 printf ("START SUMMARY OF BB INFOS\n");
1700 print_interesting_bb_infos (area);
1701 printf ("END SUMMARY OF BB INFOS\n");
1704 if (area->cfg->verbose_level >= STATISTICS_LEVEL) {
1705 printf ("STATISTICS: saved_occurrences = %d, reloaded_occurrences = %d, inserted_occurrences = %d, unaltered_occurrences = %d, added_phis = %d\n",
1706 area->saved_occurrences, area->reloaded_occurrences, area->inserted_occurrences, area->unaltered_occurrences, area->added_phis);
1709 if (area->cfg->verbose_level >= TRACE_LEVEL) {
1710 printf ("SSAPRE ENDS PROCESSING EXPRESSION ");
1711 print_expression_description (&(expression->description));
1717 * Perform all SSAPRE steps for all the expressions in the worklist
1720 process_worklist (MonoSsapreWorkArea *area, MonoSsapreExpression *expression) {
1721 if (expression != NULL) {
1722 process_worklist (area, expression->previous);
1723 process_expression (area, expression);
1724 process_worklist (area, expression->next);
1729 * Hack to apply SSAPRE only to a given method (invaluable in debugging)
1731 #define APPLY_SSAPRE_TO_SINGLE_METHOD 0
1732 #if (APPLY_SSAPRE_TO_SINGLE_METHOD)
1733 static char *mono_ssapre_method_name = NULL;
1734 static gboolean check_ssapre_method_name (MonoCompile *cfg) {
1735 if (mono_ssapre_method_name == NULL) {
1736 mono_ssapre_method_name = getenv ("MONO_SSAPRE_METHOD_NAME");
1738 if (mono_ssapre_method_name != NULL) {
1739 char *method_name = mono_method_full_name (cfg->method, TRUE);
1740 if (strstr (mono_ssapre_method_name, method_name) != NULL) {
1752 * Apply SSAPRE to a MonoCompile
1755 mono_perform_ssapre (MonoCompile *cfg) {
1756 MonoSsapreWorkArea area;
1757 MonoSsapreExpressionOccurrence *current_occurrence;
1758 int dt_dfn, descendants, block, i;
1760 #if (APPLY_SSAPRE_TO_SINGLE_METHOD)
1761 if (! check_ssapre_method_name (cfg)) return;
1765 area.mempool = mono_mempool_new ();
1767 area.num_bblocks = cfg->num_bblocks;
1768 area.bb_infos = (MonoSsapreBBInfo*) mono_mempool_alloc (area.mempool, sizeof (MonoSsapreBBInfo) * (cfg->num_bblocks));
1769 area.bb_infos_in_cfg_dfn_order = (MonoSsapreBBInfo**) mono_mempool_alloc (area.mempool, sizeof (MonoSsapreBBInfo*) * (cfg->num_bblocks));
1771 area.sizeof_bb_bitset = mono_bitset_alloc_size (cfg->num_bblocks, 0);
1772 area.expression_occurrences_buffer = mono_bitset_mem_new (mono_mempool_alloc (area.mempool, area.sizeof_bb_bitset), area.num_bblocks, 0);
1773 area.bb_iteration_buffer = mono_bitset_mem_new (mono_mempool_alloc (area.mempool, area.sizeof_bb_bitset), area.num_bblocks, 0);
1774 area.iterated_dfrontier_buffer = mono_bitset_mem_new (mono_mempool_alloc (area.mempool, area.sizeof_bb_bitset), area.num_bblocks, 0);
1775 area.left_argument_bb_bitset = mono_bitset_mem_new (mono_mempool_alloc (area.mempool, area.sizeof_bb_bitset), area.num_bblocks, 0);
1776 area.right_argument_bb_bitset = mono_bitset_mem_new (mono_mempool_alloc (area.mempool, area.sizeof_bb_bitset), area.num_bblocks, 0);
1778 area.worklist = NULL;
1780 if (area.cfg->verbose_level >= LOG_LEVEL) {
1781 printf ("SSAPRE STARTS PROCESSING METHOD %s\n", mono_method_full_name (cfg->method, TRUE));
1784 current_occurrence = (MonoSsapreExpressionOccurrence*) mono_mempool_alloc (area.mempool, sizeof (MonoSsapreExpressionOccurrence));
1787 process_bb (&area, cfg->bblocks [0], &dt_dfn, &descendants, current_occurrence);
1788 for (block = 0; block < area.num_bblocks; block++) {
1789 MonoSsapreBBInfo *bb_info = &(area.bb_infos [block]);
1790 MonoBasicBlock *bb = bb_info->bb;
1791 if (bb->idom != NULL) {
1792 bb_info->idominator = area.bb_infos_in_cfg_dfn_order [bb->idom->dfn];
1794 bb_info->idominator = NULL;
1796 for (i = 0; i < bb->in_count; i++) {
1797 bb_info->in_bb [i] = area.bb_infos_in_cfg_dfn_order [bb->in_bb [i]->dfn];
1799 for (i = 0; i < bb->out_count; i++) {
1800 bb_info->out_bb [i] = area.bb_infos_in_cfg_dfn_order [bb->out_bb [i]->dfn];
1804 if (area.cfg->verbose_level >= TRACE_LEVEL) {
1805 printf ("SSAPRE START WORKLIST\n");
1806 print_worklist (area.worklist);
1807 printf ("SSAPRE END WORKLIST\n");
1810 process_worklist (&area, area.worklist);
1812 if (area.cfg->verbose_level >= TRACE_LEVEL) {
1813 printf ("SSAPRE ENDS PROCESSING METHOD %s\n", mono_method_full_name (cfg->method, TRUE));
1816 mono_mempool_destroy (area.mempool);