if (bb_info->next_interesting_bb != NULL) {
printf (", NEXT %d [ID %d]", bb_info->next_interesting_bb->cfg_dfn, bb_info->next_interesting_bb->bb->block_num);
}
+ if (bb_info->dt_covered_by_interesting_BBs) {
+ printf (" (COVERED)");
+ } else {
+ printf (" (NEVER DOWN SAFE)");
+ }
printf ("\n");
if (bb_info->has_phi) {
printf (" PHI, class %d [ ", bb_info->phi_redundancy_class);
* (with all the info that comes from the MonoBasicBlock).
*/
static void
-process_bb (MonoSsapreWorkArea *area, MonoBasicBlock *bb, int *dt_dfn, int *upper_descendants) {
+process_bb (MonoSsapreWorkArea *area, MonoBasicBlock *bb, int *dt_dfn, int *upper_descendants, int current_depth) {
MonoSsapreBBInfo *bb_info;
int descendants;
GList *dominated_bb;
current_inst = current_inst->next;
}
+ if (current_depth > area->dt_depth) {
+ area->dt_depth = current_depth;
+ }
descendants = 0;
for (dominated_bb = g_list_first (bb->dominated); dominated_bb != NULL; dominated_bb = g_list_next (dominated_bb)) {
- process_bb (area, (MonoBasicBlock*) (dominated_bb->data), dt_dfn, &descendants);
+ process_bb (area, (MonoBasicBlock*) (dominated_bb->data), dt_dfn, &descendants, current_depth + 1);
}
bb_info->dt_descendants = descendants;
*upper_descendants += (descendants + 1);
int i;
for (i = 0; i < area->num_bblocks; i++) {
MonoSsapreBBInfo *bb_info = &(area->bb_infos [i]);
+ bb_info->dt_covered_by_interesting_BBs = FALSE;
bb_info->has_phi = FALSE;
bb_info->phi_defines_a_real_occurrence = FALSE;
bb_info->phi_is_down_safe = FALSE;
} while (change);
}
+/*
+ * See paper, section 5.1, definition of "Dominate"
+ */
+static gboolean
+dominates (MonoSsapreBBInfo *dominator, MonoSsapreBBInfo *dominated) {
+ if ((dominator->dt_dfn <= dominated->dt_dfn) && (dominated->dt_dfn <= (dominator->dt_dfn + dominator->dt_descendants))) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
/*
* See paper, figure 18, function Set_var_phis
*/
MonoSsapreBBInfo *current_bb = NULL;
MonoSsapreBBInfo *previous_interesting_bb = NULL;
int i, j, current_bb_dt_dfn;
+ int top;
+ MonoSsapreBBInfo **stack;
+ gboolean *interesting_stack;
mono_bitset_clear_all (area->expression_occurrences_buffer);
for (current_expression = expression->occurrences; current_expression != NULL; current_expression = current_expression->next) {
}
}
+ top = -1;
+ stack = (MonoSsapreBBInfo **) alloca (sizeof (MonoSsapreBBInfo *) * (area->dt_depth));
+ interesting_stack = (gboolean *) alloca (sizeof (gboolean) * (area->dt_depth));
+
+ /* Setup the list of interesting BBs, and their "DT coverage" */
for (current_bb = area->bb_infos, current_bb_dt_dfn = 0; current_bb_dt_dfn < area->num_bblocks; current_bb++, current_bb_dt_dfn++) {
+ gboolean current_bb_is_interesting;
+
if ((current_bb->first_expression_in_bb != NULL) || (current_bb->has_phi) || (current_bb->has_phi_argument)) {
+ current_bb_is_interesting = TRUE;
+
if (previous_interesting_bb != NULL) {
previous_interesting_bb->next_interesting_bb = current_bb;
} else {
area->first_interesting_bb = current_bb;
}
previous_interesting_bb = current_bb;
+ } else {
+ current_bb_is_interesting = FALSE;
}
+
+ if (top >= 0) {
+ while ((top >= 0) && (! dominates (stack [top], current_bb))) {
+ gboolean top_covers_his_idominator = ((interesting_stack [top]) || (stack [top]->dt_covered_by_interesting_BBs));
+
+ if ((top > 0) && (! top_covers_his_idominator)) {
+ stack [top - 1]->dt_covered_by_interesting_BBs = FALSE;
+ }
+
+ top--;
+ }
+ } else {
+ top = -1;
+ }
+
+ top++;
+
+ interesting_stack [top] = current_bb_is_interesting;
+ stack [top] = current_bb;
+ if (stack [top]->dt_descendants == 0) {
+ stack [top]->dt_covered_by_interesting_BBs = FALSE;
+ } else {
+ stack [top]->dt_covered_by_interesting_BBs = TRUE;
+ }
+ }
+ while (top > 0) {
+ gboolean top_covers_his_idominator = ((interesting_stack [top]) || (stack [top]->dt_covered_by_interesting_BBs));
+
+ if (! top_covers_his_idominator) {
+ stack [top - 1]->dt_covered_by_interesting_BBs = FALSE;
+ }
+
+ top--;
}
}
area->bb_on_top_of_renaming_stack->phi_argument_has_real_use = FALSE; \
} while(0)
-/*
- * See paper, section 5.1, definition of "Dominate"
- */
-static gboolean
-dominates (MonoSsapreBBInfo *dominator, MonoSsapreBBInfo *dominated) {
- if ((dominator->dt_dfn <= dominated->dt_dfn) && (dominated->dt_dfn <= (dominator->dt_dfn + dominator->dt_descendants))) {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
/*
* See paper, section 5.4.
* The two passes are coded sequentially (no separate "rename1" and "rename2" functions).
}
if (current_bb->has_phi) {
- current_bb->phi_is_down_safe = TRUE;
+ if (current_bb->dt_covered_by_interesting_BBs) {
+ current_bb->phi_is_down_safe = TRUE;
+ } else {
+ current_bb->phi_is_down_safe = FALSE;
+ }
current_bb->phi_redundancy_class = current_class;
current_class++;
PUSH_PHI_OCCURRENCE (current_bb);
current_expression->redundancy_class = phi_bb->phi_redundancy_class;
current_expression->defined_by_phi = phi_bb;
+ /* If this PHI was not "covered", it is not down safe. */
+ /* However, if the real occurrence is in the same BB, it */
+ /* actually is down safe */
+ if (phi_bb == current_bb) {
+ if (DUMP_SSAPRE) {
+ printf ("PHI in bb %d [ID %d] defined occurrence %d in the same BB, so it is down safe\n", phi_bb->cfg_dfn, phi_bb->bb->block_num, current_expression->redundancy_class);
+ }
+ phi_bb->phi_is_down_safe = TRUE;
+ }
+
/*
* Major difference from the paper here...
* Instead of maintaining "set_for_rename2" (see figure 20), we just
MonoSsapreBBInfo *current_bb = NULL;
MonoSsapreExpressionOccurrence *current_expression = NULL;
+ area->occurrences_scheduled_for_reloading = 0;
+ area->arguments_scheduled_for_insertion = 0;
+ area->dominating_arguments_scheduled_for_insertion = 0;
+
for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
if (current_bb->has_phi) {
if (current_bb->phi_can_be_available && ! current_bb->phi_is_later) {
availability_table [current_expression->redundancy_class].class_defined_by_real_occurrence = current_expression;
} else {
current_expression->reload = TRUE;
+
+ area->occurrences_scheduled_for_reloading ++;
+
current_expression->defined_by_phi = availability_table [current_expression->redundancy_class].class_defined_by_phi;
current_expression->defined_by_real_occurrence = availability_table [current_expression->redundancy_class].class_defined_by_real_occurrence;
}
(! ((current_bb->phi_argument_defined_by_phi->phi_can_be_available) && (! current_bb->phi_argument_defined_by_phi->phi_is_later)))
))) {
current_bb->phi_argument_needs_insert = TRUE;
+
+ area->arguments_scheduled_for_insertion ++;
+ if (dominates (current_bb, phi_bb)) {
+ area->dominating_arguments_scheduled_for_insertion ++;
+ }
+
current_bb->phi_argument_defined_by_real_occurrence = NULL;
current_bb->phi_argument_defined_by_phi = NULL;
} else {
}
}
+#define OP_IS_CHEAP(op) (((op)==CEE_ADD)||((op)==CEE_SUB))
+#define EXPRESSION_HAS_ICONST(d) (((d).left_argument.type==MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT)||((d).right_argument.type==MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT))
+#define EXPRESSION_IS_CHEAP(d) ((OP_IS_CHEAP ((d).opcode))&&(EXPRESSION_HAS_ICONST ((d))))
+#define REDUNDANCY_IS_SMALL(a) (((a)->occurrences_scheduled_for_reloading < 2)&&((a)->dominating_arguments_scheduled_for_insertion < 1))
+
/*
- * Perform all "finalize" steps
+ * Perform all "finalize" steps.
+ * Return TRUE if we must go on with code_motion.
*/
-static void finalize (MonoSsapreWorkArea *area) {
+static gboolean finalize (MonoSsapreWorkArea *area) {
MonoSsapreAvailabilityTableElement *availability_table = alloca (sizeof (MonoSsapreAvailabilityTableElement) * (area->number_of_classes));
int i;
}
finalize_availability_and_reload (area, availability_table);
- finalize_save (area);
+
+ /* Tuning: if the redundancy is not worth handling, give up */
+ if ((EXPRESSION_IS_CHEAP (area->current_expression->description)) && (REDUNDANCY_IS_SMALL (area))) {
+ return FALSE;
+ } else {
+ finalize_save (area);
+ return TRUE;
+ }
}
/*
down_safety (area);
compute_can_be_available (area);
compute_later (area);
- finalize (area);
- code_motion (area);
+ if (finalize (area)) {
+ code_motion (area);
+ } else {
+ if (area->cfg->verbose_level >= TRACE_LEVEL) {
+ printf ("SSAPRE CODE MOTION SKIPPED\n");
+ }
+ }
+
if (area->cfg->verbose_level >= DUMP_LEVEL) {
printf ("START DUMP OF BB INFOS\n");
if (area.cfg->verbose_level >= LOG_LEVEL) {
printf ("SSAPRE STARTS PROCESSING METHOD %s\n", mono_method_full_name (cfg->method, TRUE));
}
+ if (area.cfg->verbose_level >= DUMP_LEVEL) {
+ printf ("BEFORE SSAPRE START\n");
+ mono_print_code (area.cfg);
+ printf ("BEFORE SSAPRE END\n");
+ }
area.first_in_queue = NULL;
area.last_in_queue = NULL;
area.current_occurrence = (MonoSsapreExpressionOccurrence*) mono_mempool_alloc (area.mempool, sizeof (MonoSsapreExpressionOccurrence));
dt_dfn = 0;
descendants = 0;
- process_bb (&area, cfg->bblocks [0], &dt_dfn, &descendants);
+ area.dt_depth = 0;
+ process_bb (&area, cfg->bblocks [0], &dt_dfn, &descendants, 1);
for (block = 0; block < area.num_bblocks; block++) {
MonoSsapreBBInfo *bb_info = &(area.bb_infos [block]);
MonoBasicBlock *bb = bb_info->bb;
process_expression (&area);
}
+ if (area.cfg->verbose_level >= DUMP_LEVEL) {
+ printf ("AFTER SSAPRE START\n");
+ mono_print_code (area.cfg);
+ printf ("AFTER SSAPRE END\n");
+ }
if (area.cfg->verbose_level >= TRACE_LEVEL) {
printf ("SSAPRE ENDS PROCESSING METHOD %s\n", mono_method_full_name (cfg->method, TRUE));
}