#include <string.h>
#include <stdio.h>
+#include <math.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/opcodes.h>
printf ("INTEGER_CONSTANT %d", argument->argument.integer_constant);
break;
case MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT:
- printf ("LONG_COSTANT %lld", *(argument->argument.long_constant));
+ printf ("LONG_COSTANT %lld", (long long)*(argument->argument.long_constant));
break;
case MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT:
printf ("FLOAT_COSTANT %f", *(argument->argument.float_constant));
}
}
+#if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
+static void
+snprint_argument (GString *string, MonoSsapreExpressionArgument *argument) {
+ switch (argument->type) {
+ case MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY:
+ g_string_append_printf (string, "ANY");
+ break;
+ case MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT:
+ g_string_append_printf (string, "NONE");
+ break;
+ case MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE:
+ g_string_append_printf (string, "ORIGINAL_VARIABLE %d", argument->argument.original_variable);
+ break;
+ case MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE:
+ g_string_append_printf (string, "SSA_VARIABLE %d", argument->argument.ssa_variable);
+ break;
+ case MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT:
+ g_string_append_printf (string, "INTEGER_CONSTANT %d", argument->argument.integer_constant);
+ break;
+ case MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT:
+ g_string_append_printf (string, "LONG_COSTANT %lld", *(argument->argument.long_constant));
+ break;
+ case MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT:
+ g_string_append_printf (string, "FLOAT_COSTANT %f", *(argument->argument.float_constant));
+ break;
+ case MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT:
+ g_string_append_printf (string, "DOUBLE_COSTANT %f", *(argument->argument.double_constant));
+ break;
+ default:
+ g_string_append_printf (string, "UNKNOWN: %d", argument->type);
+ }
+}
+
+static void
+snprint_expression_description (GString *string, MonoSsapreExpressionDescription *expression_description) {
+ if (expression_description->opcode != 0) {
+ g_string_append_printf (string, "%s ([", mono_inst_name (expression_description->opcode) );
+ snprint_argument (string, &(expression_description->left_argument));
+ g_string_append_printf (string, "],[");
+ snprint_argument (string, &(expression_description->right_argument));
+ g_string_append_printf (string, "])");
+ } else {
+ g_string_append_printf (string, "ANY");
+ }
+}
+#endif
+
#define GBOOLEAN_TO_STRING(b) ((b)?"TRUE":"FALSE")
static void
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);
case CEE_LDIND_R4:
case CEE_LDIND_R8:
case CEE_LDIND_REF:
- analyze_argument (argument->inst_left, result);
+ if ((argument->inst_left->opcode == OP_LOCAL) || (argument->inst_left->opcode == OP_ARG)) {
+ result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE;
+ result->argument.ssa_variable = argument->inst_left->inst_c0;
+ } else {
+ result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
+ }
break;
case OP_ICONST:
result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT;
result->argument.long_constant = &(argument->inst_l);
break;
case OP_R4CONST:
- result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT;
- result->argument.float_constant = (float*)argument->inst_p0;
+ if (! isnan (*((float*)argument->inst_p0))) {
+ result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT;
+ result->argument.float_constant = (float*)argument->inst_p0;
+ } else {
+ result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
+ }
break;
case OP_R8CONST:
- result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT;
- result->argument.double_constant = (double*)argument->inst_p0;
- break;
- case OP_ARG:
- case OP_LOCAL:
- result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE;
- result->argument.ssa_variable = argument->inst_c0;
+ if (! isnan (*((double*)argument->inst_p0))) {
+ result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT;
+ result->argument.double_constant = (double*)argument->inst_p0;
+ } else {
+ result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
+ }
break;
default:
result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
}
}
+
/*
* Given a MonoInst, it tries to describe it as an expression.
* If this is not possible, the result will have opcode 0.
static void
analyze_expression (MonoInst *expression, MonoSsapreExpressionDescription *result) {
switch (expression->opcode) {
- case CEE_LDIND_I1:
- case CEE_LDIND_U1:
- case CEE_LDIND_I2:
- case CEE_LDIND_U2:
- case CEE_LDIND_I4:
- case CEE_LDIND_U4:
- case CEE_LDIND_I8:
- case CEE_LDIND_I:
- case CEE_LDIND_R4:
- case CEE_LDIND_R8:
- case CEE_LDIND_REF:
- analyze_expression (expression->inst_left, result);
- break;
- case CEE_SWITCH:
- case CEE_ISINST:
- case CEE_CASTCLASS:
- case OP_OUTARG:
- case OP_CALL_REG:
- case OP_FCALL_REG:
- case OP_LCALL_REG:
- case OP_VCALL_REG:
- case OP_VOIDCALL_REG:
- case CEE_CALL:
- case CEE_CALLVIRT:
- case OP_FCALL:
- case OP_FCALLVIRT:
- case OP_LCALL:
- case OP_LCALLVIRT:
- case OP_VCALL:
- case OP_VCALLVIRT:
- case OP_VOIDCALL:
- case OP_VOIDCALLVIRT:
- case OP_RENAME:
- case OP_RETARG:
-// case OP_OUTARG:
- case OP_OUTARG_REG:
- case OP_OUTARG_IMM:
- case OP_OUTARG_R4:
- case OP_OUTARG_R8:
- case OP_OUTARG_VT:
- case CEE_NOP:
- case CEE_JMP:
- case CEE_BREAK:
- case OP_COMPARE:
- case OP_COMPARE_IMM:
- case OP_FCOMPARE:
- case OP_LCOMPARE:
- case OP_ICOMPARE:
- case OP_ICOMPARE_IMM:
- result->opcode = 0;
- break;
- default:
+#define OPDEF(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) case a1:
+#include "ssapre-cee-ops.h"
+#undef OPDEF
+#define MINI_OP(a1,a2) case a1:
+#include "ssapre-mini-ops.h"
+#undef MINI_OP
if ( (expression->type == STACK_I4) ||
+ (expression->type == STACK_PTR) ||
+ (expression->type == STACK_MP) ||
(expression->type == STACK_I8) ||
(expression->type == STACK_R8) ) {
if (mono_burg_arity [expression->opcode] > 0) {
+ result->opcode = expression->opcode;
analyze_argument (expression->inst_left, &(result->left_argument));
- if (result->left_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY) {
- if (mono_burg_arity [expression->opcode] > 1) {
- analyze_argument (expression->inst_right, &(result->right_argument));
- if (result->right_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY) {
- result->opcode = expression->opcode;
- } else {
- result->opcode = 0;
- }
- } else {
- result->right_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT;
- result->opcode = expression->opcode;
- }
+ if (mono_burg_arity [expression->opcode] > 1) {
+ analyze_argument (expression->inst_right, &(result->right_argument));
} else {
- result->opcode = 0;
+ result->right_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT;
}
} else {
result->opcode = 0;
}
} else {
result->opcode = 0;
+ //~ if (expression->type != 0) {
+ //~ MonoType *type = mono_type_from_stack_type (expression);
+ //~ printf ("SSAPRE refuses opcode %s (%d) with type %s (%d)\n", mono_inst_name (expression->opcode), expression->opcode, mono_type_full_name (type), expression->type);
+ //~ } else {
+ //~ printf ("SSAPRE cannot really handle expression of opcode %s (%d)\n", mono_inst_name (expression->opcode), expression->opcode);
+ //~ }
}
- }
+ break;
+ default:
+ result->opcode = 0;
+ result->left_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
+ result->right_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
+ }
+ //~ switch (expression->opcode) {
+ //~ case CEE_ADD:
+ //~ if ((result->left_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT) &&
+ //~ (result->right_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT)) {
+ //~ break;
+ //~ }
+ //~ case CEE_LDELEMA:
+ //~ case CEE_LDLEN:
+ //~ result->opcode = 0;
+ //~ result->left_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
+ //~ result->right_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
+ //~ }
}
/*
}
}
+#if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
+static char *mono_ssapre_expression_name = NULL;
+static gboolean
+check_ssapre_expression_name (MonoSsapreWorkArea *area, MonoSsapreExpressionDescription *expression_description) {
+ if (area->expression_is_handled_father) {
+ return TRUE;
+ }
+ if (mono_ssapre_expression_name == NULL) {
+ mono_ssapre_expression_name = getenv ("MONO_SSAPRE_EXPRESSION_NAME");
+ }
+ if (mono_ssapre_expression_name != NULL) {
+ GString *expression_name = g_string_new_len ("", 256);
+ gboolean return_value;
+ snprint_expression_description (expression_name, expression_description);
+ if (strstr (expression_name->str, mono_ssapre_expression_name) != NULL) {
+ return_value = TRUE;
+ } else {
+ return_value = FALSE;
+ }
+ g_string_free (expression_name, TRUE);
+ return return_value;
+ } else {
+ return TRUE;
+ }
+}
+#endif
+
/*
- * Adds an expression to the worklist (putting the given occurrence as first
+ * Adds an expression to the worklist (putting the current occurrence as first
* occurrence of this expression).
*/
static void
-add_expression_to_worklist (MonoSsapreWorkArea *area, MonoSsapreExpressionOccurrence *occurrence) {
- MonoSsapreExpression *expression;
-
- expression = (MonoSsapreExpression*) mono_mempool_alloc (area->mempool, sizeof (MonoSsapreExpression));
+add_expression_to_worklist (MonoSsapreWorkArea *area) {
+ MonoSsapreExpressionOccurrence *occurrence = area->current_occurrence;
+ MonoSsapreExpression *expression = (MonoSsapreExpression*) mono_mempool_alloc (area->mempool, sizeof (MonoSsapreExpression));
convert_ssa_variables_to_original_names (&(expression->description), &(occurrence->description), area->cfg);
+
+#if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
+ if (! check_ssapre_expression_name (area, &(expression->description))) return;
+#endif
+
expression->type = mono_type_from_stack_type (occurrence->occurrence);
expression->occurrences = NULL;
expression->last_occurrence = NULL;
+ expression->next_in_queue = NULL;
+ if (area->last_in_queue != NULL) {
+ area->last_in_queue->next_in_queue = expression;
+ } else {
+ area->first_in_queue = expression;
+ }
+ area->last_in_queue = expression;
MONO_SSAPRE_ADD_EXPRESSION_OCCURRANCE (expression, occurrence);
area->worklist = add_expression_to_tree (area->worklist, expression);
}
/*
- * Adds an expression occurrence to the worklist.
+ * Adds the current expression occurrence to the worklist.
* If its expression is not yet in the worklist, it is created.
*/
static void
-add_occurrence_to_worklist (MonoSsapreWorkArea *area, MonoSsapreExpressionOccurrence *occurrence) {
+add_occurrence_to_worklist (MonoSsapreWorkArea *area) {
MonoSsapreExpressionDescription description;
MonoSsapreExpression *current_expression;
int comparison;
- convert_ssa_variables_to_original_names (&description, &(occurrence->description), area->cfg);
+ convert_ssa_variables_to_original_names (&description, &(area->current_occurrence->description), area->cfg);
current_expression = area->worklist;
do {
} else if (comparison < 0) {
current_expression = current_expression->previous;
} else {
- MONO_SSAPRE_ADD_EXPRESSION_OCCURRANCE (current_expression, occurrence);
+ MONO_SSAPRE_ADD_EXPRESSION_OCCURRANCE (current_expression, area->current_occurrence);
}
} else {
- add_expression_to_worklist (area, occurrence);
+ add_expression_to_worklist (area);
comparison = 0;
}
} while (comparison != 0);
+
+ area->current_occurrence = (MonoSsapreExpressionOccurrence*) mono_mempool_alloc (area->mempool, sizeof (MonoSsapreExpressionOccurrence));
}
/*
* Process a MonoInst, and of it is a valid expression add it to the worklist.
*/
-static MonoSsapreExpressionOccurrence*
-process_inst (MonoSsapreWorkArea *area, MonoInst* inst, MonoInst* previous_inst, MonoSsapreBBInfo *bb_info, MonoSsapreExpressionOccurrence *current_occurrence) {
-
- /* Ugly hack to fix missing variable definitions */
- /* (the SSA construction code should have done it already!) */
- switch (inst->opcode) {
- case CEE_STIND_REF:
- case CEE_STIND_I:
- case CEE_STIND_I4:
- case CEE_STIND_I1:
- case CEE_STIND_I2:
- case CEE_STIND_I8:
- case CEE_STIND_R4:
- case CEE_STIND_R8:
- if ((inst->inst_left->opcode == OP_LOCAL) || (inst->inst_left->opcode == OP_ARG)) {
- int variable_index = inst->inst_left->inst_c0;
-
- if (area->cfg->vars [variable_index]->def_bb == NULL) {
- if (area->cfg->verbose_level >= 4) {
- printf ("SSAPRE WARNING: variable %d has no definition, fixing.\n", variable_index);
- }
- area->cfg->vars [variable_index]->def_bb = bb_info->bb;
- }
- }
- break;
- default:
- break;
- }
+static void
+process_inst (MonoSsapreWorkArea *area, MonoInst* inst, MonoInst* previous_inst, MonoSsapreFatherExpression*** father_in_tree, MonoSsapreBBInfo *bb_info) {
+ MonoSsapreFatherExpression** left_father_in_tree = NULL;
+ MonoSsapreFatherExpression** right_father_in_tree = NULL;
if (mono_burg_arity [inst->opcode] > 0) {
- current_occurrence = process_inst (area, inst->inst_left, previous_inst, bb_info, current_occurrence);
+ process_inst (area, inst->inst_left, previous_inst, &left_father_in_tree, bb_info);
if (mono_burg_arity [inst->opcode] > 1) {
- current_occurrence = process_inst (area, inst->inst_right, previous_inst, bb_info, current_occurrence);
+ process_inst (area, inst->inst_right, previous_inst, &right_father_in_tree, bb_info);
}
}
- analyze_expression (inst, &(current_occurrence->description));
- if (current_occurrence->description.opcode != 0) {
- current_occurrence->occurrence = inst;
- current_occurrence->previous_tree = previous_inst;
- current_occurrence->bb_info = bb_info;
- current_occurrence->is_first_in_bb = FALSE;
- current_occurrence->is_last_in_bb = FALSE;
- add_occurrence_to_worklist (area, current_occurrence);
- current_occurrence = (MonoSsapreExpressionOccurrence*) mono_mempool_alloc (area->mempool, sizeof (MonoSsapreExpressionOccurrence));
+ analyze_expression (inst, &(area->current_occurrence->description));
+ if (area->current_occurrence->description.opcode != 0) {
+ if ((left_father_in_tree != NULL) || (right_father_in_tree != NULL)) {
+ MonoSsapreFatherExpression *current_inst_as_father = (MonoSsapreFatherExpression*) mono_mempool_alloc (area->mempool, sizeof (MonoSsapreFatherExpression));
+ current_inst_as_father->father_occurrence = inst;
+ current_inst_as_father->grand_father = NULL;
+ *father_in_tree = &(current_inst_as_father->grand_father);
+ if (left_father_in_tree != NULL) {
+ *left_father_in_tree = current_inst_as_father;
+ }
+ if (right_father_in_tree != NULL) {
+ *right_father_in_tree = current_inst_as_father;
+ }
+ if (DUMP_SSAPRE) {
+ printf ("Expression '");
+ mono_print_tree (inst);
+ printf ("' is a potential father ( ");
+ if (left_father_in_tree != NULL) {
+ printf ("LEFT ");
+ }
+ if (right_father_in_tree != NULL) {
+ printf ("RIGHT ");
+ }
+ printf (")\n");
+ }
+ } else if ((area->current_occurrence->description.left_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY) &&
+ (area->current_occurrence->description.right_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY)) {
+ area->current_occurrence->occurrence = inst;
+ area->current_occurrence->previous_tree = previous_inst;
+ area->current_occurrence->bb_info = bb_info;
+ area->current_occurrence->is_first_in_bb = FALSE;
+ area->current_occurrence->is_last_in_bb = FALSE;
+
+ area->current_occurrence->father_in_tree = NULL;
+ *father_in_tree = &(area->current_occurrence->father_in_tree);
+
+ add_occurrence_to_worklist (area);
+ } else {
+ *father_in_tree = NULL;
+ }
+ } else {
+ *father_in_tree = NULL;
}
-
- return current_occurrence;
}
/*
* auxiliary MonoSsapreBBInfo fields (dt_dfn, dt_descendants) are initialized
* (with all the info that comes from the MonoBasicBlock).
*/
-static MonoSsapreExpressionOccurrence*
-process_bb (MonoSsapreWorkArea *area, MonoBasicBlock *bb, int *dt_dfn, int *upper_descendants, MonoSsapreExpressionOccurrence *current_occurrence) {
+static void
+process_bb (MonoSsapreWorkArea *area, MonoBasicBlock *bb, int *dt_dfn, int *upper_descendants, int current_depth) {
MonoSsapreBBInfo *bb_info;
int descendants;
GList *dominated_bb;
MonoInst* current_inst;
MonoInst* previous_inst;
+ MonoSsapreFatherExpression** dummy_father_in_tree;
bb_info = &(area->bb_infos [*dt_dfn]);
bb_info->dt_dfn = *dt_dfn;
bb_info->bb = bb;
bb_info->in_bb = (MonoSsapreBBInfo**) mono_mempool_alloc (area->mempool, sizeof (MonoSsapreBBInfo*) * (bb->in_count));
bb_info->out_bb = (MonoSsapreBBInfo**) mono_mempool_alloc (area->mempool, sizeof (MonoSsapreBBInfo*) * (bb->out_count));
- bb_info->phi_arguments_classes = (gssize*) mono_mempool_alloc (area->mempool, sizeof (gssize) * (bb->in_count));
+ bb_info->phi_arguments_classes = (int*) mono_mempool_alloc (area->mempool, sizeof (int) * (bb->in_count));
bb_info->phi_insertion_point = NULL;
current_inst = bb->code;
previous_inst = NULL;
while (current_inst != NULL) {
+ /* Ugly hack to fix missing variable definitions */
+ /* (the SSA construction code should have done it already!) */
+ switch (current_inst->opcode) {
+ case CEE_STIND_REF:
+ case CEE_STIND_I:
+ case CEE_STIND_I4:
+ case CEE_STIND_I1:
+ case CEE_STIND_I2:
+ case CEE_STIND_I8:
+ case CEE_STIND_R4:
+ case CEE_STIND_R8:
+ if ((current_inst->inst_left->opcode == OP_LOCAL) || (current_inst->inst_left->opcode == OP_ARG)) {
+ int variable_index = current_inst->inst_left->inst_c0;
+
+ if (area->cfg->vars [variable_index]->def_bb == NULL) {
+ if (area->cfg->verbose_level >= 4) {
+ printf ("SSAPRE WARNING: variable %d has no definition, fixing.\n", variable_index);
+ }
+ area->cfg->vars [variable_index]->def_bb = bb_info->bb;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
if (is_phi_definition (current_inst)) {
bb_info->phi_insertion_point = current_inst;
}
- current_occurrence = process_inst (area, current_inst, previous_inst, bb_info, current_occurrence);
+
+ if (mono_burg_arity [current_inst->opcode] > 0) {
+ process_inst (area, current_inst->inst_left, previous_inst, &dummy_father_in_tree, bb_info);
+ if (mono_burg_arity [current_inst->opcode] > 1) {
+ process_inst (area, current_inst->inst_right, previous_inst, &dummy_father_in_tree, bb_info);
+ }
+ }
+
previous_inst = current_inst;
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)) {
- current_occurrence = process_bb (area, (MonoBasicBlock*) (dominated_bb->data), dt_dfn, &descendants, current_occurrence);
+ process_bb (area, (MonoBasicBlock*) (dominated_bb->data), dt_dfn, &descendants, current_depth + 1);
}
bb_info->dt_descendants = descendants;
*upper_descendants += (descendants + 1);
-
- return current_occurrence;
}
/*
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).
/* This loop is "rename1" */
for (current_bb = area->first_interesting_bb, previous_bb = NULL; current_bb != NULL; previous_bb = current_bb, current_bb = current_bb->next_interesting_bb) {
- if ((previous_bb != NULL) && ! dominates (previous_bb, current_bb)) {
- if ((area->bb_on_top_of_renaming_stack != NULL) && (area->top_of_renaming_stack == NULL) && (previous_bb->phi_argument_has_real_use == FALSE)) {
- if (TRACE_SSAPRE) {
- printf ("Clearing down safe in PHI %d because of backtracking (previous block is [bb %d [ID %d]])\n",
- area->bb_on_top_of_renaming_stack->phi_redundancy_class, previous_bb->cfg_dfn, previous_bb->bb->block_num);
+ if (previous_bb != NULL) {
+ if (! dominates (previous_bb, current_bb)) {
+ /* This means we are backtracking in the dominator tree */
+ MonoSsapreBBInfo *first_interesting_dominator = current_bb->idominator;
+ while ((first_interesting_dominator->next_interesting_bb == NULL) && (first_interesting_dominator->idominator != NULL)) {
+ first_interesting_dominator = first_interesting_dominator->idominator;
}
- area->bb_on_top_of_renaming_stack->phi_is_down_safe = FALSE;
- }
- while ((area->bb_on_top_of_renaming_stack != NULL) && ! dominates (area->bb_on_top_of_renaming_stack, current_bb)) {
- MonoSsapreBBInfo *top_bb = area->bb_on_top_of_renaming_stack;
- if (top_bb->next_in_renaming_stack != NULL) {
- area->top_of_renaming_stack = top_bb->next_in_renaming_stack->top_of_local_renaming_stack;
- } else {
- area->top_of_renaming_stack = NULL;
+ current_bb->phi_argument_has_real_use = first_interesting_dominator->phi_argument_has_real_use;
+
+ if ((area->bb_on_top_of_renaming_stack != NULL) && (area->top_of_renaming_stack == NULL) && (previous_bb->phi_argument_has_real_use == FALSE)) {
+ if (TRACE_SSAPRE) {
+ printf ("Clearing down safe in PHI %d because of backtracking (current block is [bb %d [ID %d]], previous block is [bb %d [ID %d]])\n",
+ area->bb_on_top_of_renaming_stack->phi_redundancy_class, current_bb->cfg_dfn, current_bb->bb->block_num, previous_bb->cfg_dfn, previous_bb->bb->block_num);
+ }
+ area->bb_on_top_of_renaming_stack->phi_is_down_safe = FALSE;
}
- area->bb_on_top_of_renaming_stack = top_bb->next_in_renaming_stack;
+ while ((area->bb_on_top_of_renaming_stack != NULL) && ! dominates (area->bb_on_top_of_renaming_stack, current_bb)) {
+ MonoSsapreBBInfo *top_bb = area->bb_on_top_of_renaming_stack;
+ if (top_bb->next_in_renaming_stack != NULL) {
+ area->top_of_renaming_stack = top_bb->next_in_renaming_stack->top_of_local_renaming_stack;
+ } else {
+ area->top_of_renaming_stack = NULL;
+ }
+ area->bb_on_top_of_renaming_stack = top_bb->next_in_renaming_stack;
+ }
+ if (DUMP_SSAPRE) {
+ printf ("Backtracked, getting real use flag from bb %d [ID %d], current top of the stack is class ",
+ first_interesting_dominator->cfg_dfn, first_interesting_dominator->bb->block_num);
+ if (area->top_of_renaming_stack != NULL) {
+ printf ("%d\n", area->top_of_renaming_stack->redundancy_class);
+ } else if (area->bb_on_top_of_renaming_stack != NULL) {
+ printf ("%d\n", area->bb_on_top_of_renaming_stack->phi_redundancy_class);
+ } else {
+ printf ("BOTTOM\n");
+ }
+ }
+ } else {
+ /* With no backtracking we just propagate the flag */
+ current_bb->phi_argument_has_real_use = previous_bb->phi_argument_has_real_use;
}
- }
- if (current_bb->idominator != NULL) {
- current_bb->phi_argument_has_real_use = current_bb->idominator->phi_argument_has_real_use;
} else {
+ /* Start condition */
current_bb->phi_argument_has_real_use = FALSE;
}
+ if (DUMP_SSAPRE) {
+ printf ("Real use flag is %s at the beginning of block [bb %d [ID %d]]\n",
+ GBOOLEAN_TO_STRING (current_bb->phi_argument_has_real_use), current_bb->cfg_dfn, current_bb->bb->block_num);
+ }
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);
+ if (TRACE_SSAPRE) {
+ printf ("Assigning class %d to PHI in bb %d [ID %d]\n",
+ current_bb->phi_redundancy_class, current_bb->cfg_dfn, current_bb->bb->block_num);
+ }
}
for (current_expression = current_bb->first_expression_in_bb; (current_expression != NULL) && (current_expression->bb_info == current_bb); current_expression = current_expression->next) {
(current_expression->description.right_argument.argument.ssa_variable == top->description.right_argument.argument.ssa_variable))) {
current_expression->redundancy_class = top->redundancy_class;
current_expression->defined_by_real_occurrence = top;
+ if (DUMP_SSAPRE) {
+ printf ("Using class %d for occurrence '", current_expression->redundancy_class);
+ print_expression_description (&(current_expression->description));
+ printf ("' in bb %d [ID %d]\n", current_bb->cfg_dfn, current_bb->bb->block_num);
+ }
} else {
current_expression->redundancy_class = current_class;
current_class++;
current_expression->defined_by_real_occurrence = NULL;
PUSH_REAL_OCCURRENCE (current_expression);
+ if (TRACE_SSAPRE) {
+ printf ("Assigning class %d to occurrence '", current_expression->redundancy_class);
+ print_expression_description (&(current_expression->description));
+ printf ("' in bb %d [ID %d]\n", current_bb->cfg_dfn, current_bb->bb->block_num);
+ }
}
current_expression->defined_by_phi = NULL;
} else if (area->bb_on_top_of_renaming_stack != NULL) {
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
right_argument_version, phi_bb, phi_argument);
}
}
+ if (DUMP_SSAPRE) {
+ printf ("Using class %d for occurrence '", current_expression->redundancy_class);
+ print_expression_description (&(current_expression->description));
+ printf ("' in bb %d [ID %d] (Real use flag is now TRUE)\n", current_bb->cfg_dfn, current_bb->bb->block_num);
+ }
} else {
current_expression->redundancy_class = current_class;
current_class++;
PUSH_REAL_OCCURRENCE (current_expression);
phi_bb->phi_is_down_safe = FALSE;
if (TRACE_SSAPRE) {
+ printf ("Assigning class %d to occurrence '", current_expression->redundancy_class);
+ print_expression_description (&(current_expression->description));
+ printf ("' in bb %d [ID %d]\n", current_bb->cfg_dfn, current_bb->bb->block_num);
printf ("Clearing down safe in PHI %d because of real occurrence %d\n",
phi_bb->phi_redundancy_class, current_expression->redundancy_class);
}
current_expression->defined_by_real_occurrence = NULL;
current_expression->defined_by_phi = NULL;
PUSH_REAL_OCCURRENCE (current_expression);
+ if (TRACE_SSAPRE) {
+ printf ("Assigning class %d to occurrence '", current_expression->redundancy_class);
+ print_expression_description (&(current_expression->description));
+ printf ("' in bb %d [ID %d]\n", current_bb->cfg_dfn, current_bb->bb->block_num);
+ }
}
}
} else {
current_bb->phi_argument_class = BOTTOM_REDUNDANCY_CLASS;
}
+ if ((DUMP_SSAPRE) && (current_bb->phi_argument_class != BOTTOM_REDUNDANCY_CLASS)) {
+ printf ("Temporarily using class %d for PHI argument in bb %d [ID %d]\n",
+ current_bb->phi_argument_class, current_bb->cfg_dfn, current_bb->bb->block_num);
+ }
}
}
if ((area->bb_on_top_of_renaming_stack != NULL) && (area->top_of_renaming_stack == NULL) && (previous_bb->phi_argument_has_real_use == FALSE)) {
current_bb->phi_argument_defined_by_phi->phi_is_down_safe = FALSE;
}
current_bb->phi_argument_has_real_use = FALSE;
+
+ if (DUMP_SSAPRE) {
+ printf ("Cleared real use flag in block [bb %d [ID %d]] because phi argument class is now BOTTOM\n",
+ current_bb->cfg_dfn, current_bb->bb->block_num);
+ }
}
}
}
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)) {
int i;
MonoSsapreBBInfo *phi = phi_argument->phi_argument_defined_by_phi;
-// if (TRACE_SSAPRE) {
-// printf ("Clearing down safe in PHI %d inside reset_down_safe\n", phi->phi_redundancy_class);
-// }
phi->phi_is_down_safe = FALSE;
for (i = 0; i < phi->in_count; i++) {
reset_down_safe (phi->in_bb [i]);
reset_can_be_available (MonoSsapreWorkArea *area, MonoSsapreBBInfo *phi) {
MonoSsapreBBInfo *current_bb = NULL;
+ if (DUMP_SSAPRE) {
+ printf ("Resetting availability for PHI %d in block [bb %d [ID %d]]\n",
+ phi->phi_redundancy_class, phi->cfg_dfn, phi->bb->block_num);
+ }
+
phi->phi_can_be_available = FALSE;
for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
if (current_bb->has_phi) {
}
if (phi_is_interesting) {
+ if (DUMP_SSAPRE) {
+ printf ("Availability computation working on PHI %d in block [bb %d [ID %d]]\n",
+ current_bb->phi_redundancy_class, current_bb->cfg_dfn, current_bb->bb->block_num);
+ }
reset_can_be_available (area, current_bb);
}
}
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;
+ }
}
/*
* Create a MonoInst that represents an expression
*/
static MonoInst*
-create_expression (MonoSsapreWorkArea *area, MonoSsapreExpressionDescription *expression) {
+create_expression (MonoSsapreWorkArea *area, MonoSsapreExpressionDescription *expression, MonoInst *prototype_occurrence) {
MonoInst *result;
NEW_INST (result, expression->opcode);
+ *result = *prototype_occurrence;
result->inst_left = create_expression_argument (area, &(expression->left_argument));
result->inst_right = create_expression_argument (area, &(expression->right_argument));
return result;
}
+/*
+ * Handles the father expression of a MonoInst that has been turned
+ * into a load (eventually inserting it into the worklist).
+ * Assumes "current_expression->father_in_tree != NULL".
+ */
+static void
+handle_father_expression (MonoSsapreWorkArea *area, MonoSsapreExpressionOccurrence *current_expression, MonoInst *previous_tree) {
+ if (DUMP_SSAPRE) {
+ printf ("After reload, father expression becomes ");
+ mono_print_tree_nl (current_expression->father_in_tree->father_occurrence);
+ }
+
+ analyze_expression (current_expression->father_in_tree->father_occurrence, &(area->current_occurrence->description));
+ if ((area->current_occurrence->description.opcode != 0) &&
+ (area->current_occurrence->description.left_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY) &&
+ (area->current_occurrence->description.right_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY)) {
+ area->current_occurrence->occurrence = current_expression->father_in_tree->father_occurrence;
+ area->current_occurrence->previous_tree = previous_tree;
+ area->current_occurrence->father_in_tree = current_expression->father_in_tree->grand_father;
+ area->current_occurrence->bb_info = current_expression->bb_info;
+ area->current_occurrence->is_first_in_bb = FALSE;
+ area->current_occurrence->is_last_in_bb = FALSE;
+ add_occurrence_to_worklist (area);
+ }
+}
+
/*
* See paper, section 3.6
*/
static void code_motion (MonoSsapreWorkArea *area) {
MonoSsapreBBInfo *current_bb = NULL;
MonoSsapreExpressionOccurrence *current_expression = NULL;
+ gssize original_variable_index = BOTTOM_REDUNDANCY_CLASS;
+ MonoInst prototype_occurrence;
+ prototype_occurrence.opcode = 0;
for (current_bb = area->first_interesting_bb; current_bb != NULL; current_bb = current_bb->next_interesting_bb) {
if ((current_bb->has_phi) && (current_bb->phi_can_be_available && ! current_bb->phi_is_later)) {
MonoInst *new_var = mono_compile_create_var (area->cfg, area->current_expression->type, OP_LOCAL);
current_bb->phi_variable_index = new_var->inst_c0;
+ if (original_variable_index == BOTTOM_REDUNDANCY_CLASS) {
+ original_variable_index = new_var->inst_c0;
+ }
+ area->cfg->vars [new_var->inst_c0]->reg = original_variable_index;
+ area->cfg->vars [new_var->inst_c0]->def_bb = current_bb->bb;
} else {
current_bb->phi_variable_index = BOTTOM_REDUNDANCY_CLASS;
}
for (current_expression = current_bb->first_expression_in_bb; (current_expression != NULL) && (current_expression->bb_info == current_bb); current_expression = current_expression->next) {
+ if (prototype_occurrence.opcode == 0) {
+ prototype_occurrence = *(current_expression->occurrence);
+ }
if (current_expression->save) {
MonoInst *new_var = mono_compile_create_var (area->cfg, area->current_expression->type, OP_LOCAL);
current_expression->variable_index = new_var->inst_c0;
+ if (original_variable_index == BOTTOM_REDUNDANCY_CLASS) {
+ original_variable_index = new_var->inst_c0;
+ }
+ area->cfg->vars [new_var->inst_c0]->reg = original_variable_index;
+ area->cfg->vars [new_var->inst_c0]->def_bb = current_bb->bb;
} else {
current_expression->variable_index = BOTTOM_REDUNDANCY_CLASS;
}
if ((current_bb->has_phi_argument) && (current_bb->phi_argument_needs_insert)) {
MonoInst *new_var = mono_compile_create_var (area->cfg, area->current_expression->type, OP_LOCAL);
current_bb->phi_argument_variable_index = new_var->inst_c0;
+ if (original_variable_index == BOTTOM_REDUNDANCY_CLASS) {
+ original_variable_index = new_var->inst_c0;
+ }
+ area->cfg->vars [new_var->inst_c0]->reg = original_variable_index;
+ area->cfg->vars [new_var->inst_c0]->def_bb = current_bb->bb;
} else {
current_bb->phi_argument_variable_index = BOTTOM_REDUNDANCY_CLASS;
}
int in_bb;
NEW_INST (phi, OP_PHI);
+ phi->inst_c0 = area->cfg->vars [current_bb->phi_variable_index]->reg;
phi->inst_phi_args = mono_mempool_alloc (area->cfg->mempool, (sizeof (int) * ((current_bb->in_count) + 1)));
phi->inst_phi_args [0] = current_bb->in_count;
for (in_bb = 0; in_bb < current_bb->in_count; in_bb++) {
store->next = current_bb->bb->code;
current_bb->bb->code = store;
}
+ area->cfg->vars [current_bb->phi_variable_index]->def = store;
current_bb->phi_insertion_point = store;
area->added_phis ++;
for (current_expression = current_bb->first_expression_in_bb; (current_expression != NULL) && (current_expression->bb_info == current_bb); current_expression = current_expression->next) {
gboolean altered = FALSE;
- if (current_expression->reload) {
- gssize variable_index;
- if (current_expression->defined_by_phi != NULL) {
- variable_index = current_expression->defined_by_phi->phi_variable_index;
- } else if (current_expression->defined_by_real_occurrence != NULL) {
- variable_index = current_expression->defined_by_real_occurrence->variable_index;
- } else {
- variable_index = BOTTOM_REDUNDANCY_CLASS;
- g_assert_not_reached ();
- }
- mono_compile_make_var_load (area->cfg, current_expression->occurrence, variable_index);
-
- area->reloaded_occurrences ++;
- altered = TRUE;
- }
if (current_expression->save) {
MonoInst *store;
MonoInst *moved_expression = mono_mempool_alloc (area->cfg->mempool, sizeof (MonoInst));
store->next = current_bb->bb->code;
current_bb->bb->code = store;
}
+ area->cfg->vars [current_expression->variable_index]->def = store;
mono_compile_make_var_load (area->cfg, current_expression->occurrence, current_expression->variable_index);
-
+ if (current_expression->father_in_tree != NULL) {
+ handle_father_expression (area, current_expression, store);
+ }
+
area->saved_occurrences ++;
altered = TRUE;
}
+ if (current_expression->reload) {
+ gssize variable_index;
+ if (current_expression->defined_by_phi != NULL) {
+ variable_index = current_expression->defined_by_phi->phi_variable_index;
+ } else if (current_expression->defined_by_real_occurrence != NULL) {
+ variable_index = current_expression->defined_by_real_occurrence->variable_index;
+ } else {
+ variable_index = BOTTOM_REDUNDANCY_CLASS;
+ g_assert_not_reached ();
+ }
+ mono_compile_make_var_load (area->cfg, current_expression->occurrence, variable_index);
+ if (current_expression->father_in_tree != NULL) {
+ handle_father_expression (area, current_expression, current_expression->previous_tree);
+ }
+
+ area->reloaded_occurrences ++;
+ altered = TRUE;
+ }
if (! altered) {
area->unaltered_occurrences ++;
}
expression_description.right_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE;
}
- inserted_expression = create_expression (area, &expression_description);
+ inserted_expression = create_expression (area, &expression_description, &prototype_occurrence);
store = mono_compile_create_var_store (area->cfg, current_bb->phi_argument_variable_index, inserted_expression);
+ area->cfg->vars [current_bb->phi_argument_variable_index]->def = store;
store->next = NULL;
mono_add_ins_to_end (current_bb->bb, store);
}
/*
- * Perform all SSAPRE steps for an expression
+ * Perform all SSAPRE steps for the current expression
*/
static void
-process_expression (MonoSsapreWorkArea *area, MonoSsapreExpression *expression) {
- if (area->cfg->verbose_level >= TRACE_LEVEL) {
+process_expression (MonoSsapreWorkArea *area) {
+ MonoSsapreExpression *expression = area->current_expression;
+
+ if (area->cfg->verbose_level >= STATISTICS_LEVEL) {
printf ("SSAPRE STARTS PROCESSING EXPRESSION ");
print_expression_description (&(expression->description));
printf ("\n");
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");
}
}
-/*
- * Perform all SSAPRE steps for all the expressions in the worklist
- */
-static void
-process_worklist (MonoSsapreWorkArea *area, MonoSsapreExpression *expression) {
- if (expression != NULL) {
- process_worklist (area, expression->previous);
- process_expression (area, expression);
- process_worklist (area, expression->next);
- }
-}
-
-/*
- * Hack to apply SSAPRE only to a given method (invaluable in debugging)
- */
-#define APPLY_SSAPRE_TO_SINGLE_METHOD 0
-#if (APPLY_SSAPRE_TO_SINGLE_METHOD)
-static char *mono_ssapre_method_name = NULL;
+#if (MONO_APPLY_SSAPRE_TO_SINGLE_METHOD)
+static char*
+mono_ssapre_method_name = NULL;
static gboolean check_ssapre_method_name (MonoCompile *cfg) {
if (mono_ssapre_method_name == NULL) {
mono_ssapre_method_name = getenv ("MONO_SSAPRE_METHOD_NAME");
}
if (mono_ssapre_method_name != NULL) {
char *method_name = mono_method_full_name (cfg->method, TRUE);
- if (strstr (mono_ssapre_method_name, method_name) != NULL) {
+ if (strstr (method_name, mono_ssapre_method_name) != NULL) {
return TRUE;
} else {
return FALSE;
void
mono_perform_ssapre (MonoCompile *cfg) {
MonoSsapreWorkArea area;
- MonoSsapreExpressionOccurrence *current_occurrence;
int dt_dfn, descendants, block, i;
-#if (APPLY_SSAPRE_TO_SINGLE_METHOD)
+#if (MONO_APPLY_SSAPRE_TO_SINGLE_METHOD)
if (! check_ssapre_method_name (cfg)) return;
#endif
+#if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
+ area.expression_is_handled_father = FALSE;
+#endif
area.cfg = cfg;
area.mempool = mono_mempool_new ();
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");
+ }
- current_occurrence = (MonoSsapreExpressionOccurrence*) mono_mempool_alloc (area.mempool, sizeof (MonoSsapreExpressionOccurrence));
+ 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, current_occurrence);
+ 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;
printf ("SSAPRE END WORKLIST\n");
}
- process_worklist (&area, area.worklist);
+#if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
+ area.expression_is_handled_father = TRUE;
+#endif
+ for (area.current_expression = area.first_in_queue; area.current_expression != NULL; area.current_expression = area.current_expression->next_in_queue) {
+ 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));
}