Преглед на файлове

2004-07-12 Massimiliano Mantione <[email protected]>

	* mono/mini/abcremoval.c: Rewritten most of ABC removal.
	* mono/mini/abcremoval.h: Rewritten most of ABC removal.
	* mono/mini/build_relations_propagation_table.pl: Deleted (unneeded after the rewrite).
	* mono/mini/propagated_relations_table.def: Deleted (unneeded after the rewrite).

svn path=/trunk/mono/; revision=31034
Massimiliano Mantione преди 21 години
родител
ревизия
8a01835f45
променени са 5 файла, в които са добавени 1087 реда и са изтрити 974 реда
  1. 7 0
      ChangeLog
  2. 807 732
      mono/mini/abcremoval.c
  3. 273 52
      mono/mini/abcremoval.h
  4. 0 126
      mono/mini/build_relations_propagation_table.pl
  5. 0 64
      mono/mini/propagated_relations_table.def

+ 7 - 0
ChangeLog

@@ -1,3 +1,10 @@
+2004-07-12  Massimiliano Mantione  <[email protected]>
+
+	* mono/mini/abcremoval.c: Rewritten most of ABC removal.
+	* mono/mini/abcremoval.h: Rewritten most of ABC removal.
+	* mono/mini/build_relations_propagation_table.pl: Deleted (unneeded after the rewrite).
+	* mono/mini/propagated_relations_table.def: Deleted (unneeded after the rewrite).
+
 2004-07-03  Zoltan Varga  <[email protected]>
 
 	* configure.in: Add --with-tls option to replace the misnamed 

+ 807 - 732
mono/mini/abcremoval.c

@@ -13,7 +13,6 @@
 #include <mono/metadata/mempool.h>
 #include <mono/metadata/opcodes.h>
 
-#include "mini.h"
 #include "inssel.h"
 
 #include "abcremoval.h"
@@ -23,38 +22,41 @@ extern guint8 mono_burg_arity [];
 #define TRACE_ABC_REMOVAL (verbose_level > 2)
 #define REPORT_ABC_REMOVAL (verbose_level > 0)
 
-#define CHEAT_AND_REMOVE_ALL_CHECKS 0
-
+/*
+ * A little hack for the verbosity level.
+ * The verbosity level is stored in the cfg, but not all functions that must
+ * print something see the cfg, so we store the verbosity level here at the
+ * beginning of the algorithm.
+ * This is not thread safe (does not handle correctly different verbosity
+ * levels in different threads), and is not exact in case of dynamic changes
+ * of the verbosity level...
+ * Anyway, this is not needed, all that can happen is that something more
+ * (or less) is logged, the result is in any case correct.
+ */
 static int verbose_level;
 
-#if (!CHEAT_AND_REMOVE_ALL_CHECKS)
-
-
-#define IS_SUMMARIZED_VALUE_CONSTANT(value) ((value).value_type==MONO_CONSTANT_SUMMARIZED_VALUE)
-#define IS_SUMMARIZED_VALUE_VARIABLE(value) ((value).value_type==MONO_VARIABLE_SUMMARIZED_VALUE)
 
 #define RELATION_BETWEEN_VALUES(value,related_value) (\
 	((value) > (related_value))? MONO_GT_RELATION :\
 	(((value) < (related_value))? MONO_LT_RELATION : MONO_EQ_RELATION))
 
 #define MAKE_VALUE_ANY(v) do{\
-		(v)->relation_with_zero = MONO_ANY_RELATION;\
-		(v)->relation_with_one = MONO_ANY_RELATION;\
-		(v)->relation_with_value = MONO_ANY_RELATION;\
-		(v)->value_type = MONO_CONSTANT_SUMMARIZED_VALUE;\
-		(v)->value.constant = 0;\
+		(v).type = MONO_ANY_SUMMARIZED_VALUE;\
+	} while (0)
+
+#define MAKE_VALUE_RELATION_ANY(r) do{\
+		(r)->relation = MONO_ANY_RELATION;\
+		MAKE_VALUE_ANY((r)->related_value);\
+	} while (0)
+
+#define INITIALIZE_VALUE_RELATION(r) do{\
+		MAKE_VALUE_RELATION_ANY((r));\
+		(r)->next = NULL;\
 	} while (0)
 
 #define MONO_NEGATED_RELATION(r) ((~(r))&MONO_ANY_RELATION)
 #define MONO_SYMMETRIC_RELATION(r) (((r)&MONO_EQ_RELATION)|(((r)&MONO_LT_RELATION)<<1)|((r&MONO_GT_RELATION)>>1))
 
-#define RELATION_ADDS_INFORMATION(r,r_maybe_adds_information) ((r)&(~(r_maybe_adds_information)))
-
-unsigned char propagated_relations_table [] = {
-	#include "propagated_relations_table.def"
-	MONO_ANY_RELATION
-};
-#define PROPAGATED_RELATION(r,r_to_propagate) (propagated_relations_table [((r)<<3)|(r_to_propagate)])
 
 
 static void
@@ -84,147 +86,137 @@ print_relation (int relation) {
 
 static void
 print_summarized_value (MonoSummarizedValue *value) {
-	printf ("relation_with_zero: ");
-	print_relation (value->relation_with_zero);
-	printf ("\n");
-	printf ("relation_with_one: ");
-	print_relation (value->relation_with_one);
-	printf ("\n");
-	printf ("relation_with_value: ");
-	print_relation (value->relation_with_value);
-	printf ("\n");
-	switch (value->value_type) {
+	switch (value->type) {
+	case MONO_ANY_SUMMARIZED_VALUE:
+		printf ("ANY");
+		break;
 	case MONO_CONSTANT_SUMMARIZED_VALUE:
-		printf ("Constant value: %d\n", value->value.constant);
+		printf ("CONSTANT %d", value->value.constant.value);
 		break;
 	case MONO_VARIABLE_SUMMARIZED_VALUE:
-		printf ("Variable value: %d\n", value->value.variable);
+		printf ("VARIABLE %d, delta %d", value->value.variable.variable, value->value.variable.delta);
 		break;
 	case MONO_PHI_SUMMARIZED_VALUE: {
-		int i;
-		printf ("PHI value: (");
-		for (i = 0; i < *(value->value.phi_variables); i++) {
-			if (i) printf (",");
-			printf ("%d", *(value->value.phi_variables + i + 1));
+		int phi;
+		printf ("PHI (");
+		for (phi = 0; phi < value->value.phi.number_of_alternatives; phi++) {
+			if (phi) printf (",");
+			printf ("%d", value->value.phi.phi_alternatives [phi]);
 		}
-		printf (")\n");
+		printf (")");
 		break;
 	}
 	default:
-		printf ("Unknown value type: %d\n", value->value_type);
+		g_assert_not_reached ();
 	}
 }
 
 static void
-print_branch_condition (MonoBranchCondition *condition, int n) {
-	printf ("Branch condition %d, on variable %d\n", n, condition->variable);
-	print_summarized_value (&(condition->value));
-}
-
-static void
-print_branch_data (MonoBranchData *branch, int n) {
-	int i;
-	printf ("Branch %d, destination BB %d [dfn %d], conditions %d\n",
-		n, branch->destination_block->block_num, branch->destination_block->dfn, branch->number_of_conditions);
-	for (i = 0; i < branch->number_of_conditions; i++) {
-		print_branch_condition (&(branch->conditions [i]), i);
-	}
+print_summarized_value_relation (MonoSummarizedValueRelation *relation) {
+	printf ("Relation ");
+	print_relation (relation->relation);
+	printf (" with value ");
+	print_summarized_value (&(relation->related_value));
 }
 
+#if 0
 static void
-print_summarized_block (MonoSummarizedBasicBlock *block) {
-	int i;
-	printf ("Summarization of BB %d [dfn %d] (has array accesses: %d), branches: %d\n",
-		block->block->block_num, block->block->dfn, block->has_array_access_instructions, block->number_of_branches);
-	for (i = 0; i < block->number_of_branches; i++) {
-		print_branch_data (&(block->branches [i]), i);
+print_summarized_value_relation_chain (MonoSummarizedValueRelation *relation) {
+	printf ("Relations:\n");
+	while (relation) {
+		print_summarized_value_relation (relation);
+		printf ("\n");
+		relation = relation->next;
 	}
 }
+#endif
 
 static void
-print_variable_relations (MonoVariableRelations *relations, gssize variable, int n) {
-	int i;
-	int significantRelations = 0;
-	for (i = 0; i < n; i++) {
-		if (relations->relations_with_variables [i] != MONO_ANY_RELATION) {
-			significantRelations++;
+print_evaluation_context_status (MonoRelationsEvaluationStatus status) {
+	if (status == MONO_RELATIONS_EVALUATION_NOT_STARTED) {
+		printf ("EVALUATION_NOT_STARTED");
+	} else {
+		gboolean print_or = FALSE;
+		
+		printf ("(");
+		if (status & MONO_RELATIONS_EVALUATION_IN_PROGRESS) {
+			if (print_or) printf ("|");
+			printf ("EVALUATION_IN_PROGRESS");
+			print_or = TRUE;
 		}
-	}
-	if ((relations->relation_with_zero != MONO_ANY_RELATION) ||
-			(relations->relation_with_one != MONO_ANY_RELATION) ||
-			(significantRelations > 0)) {
-		printf ("Relations for variable %d:\n", variable);
-		if (relations->relation_with_zero != MONO_ANY_RELATION) {
-			printf ("relation_with_zero: ");
-			print_relation (relations->relation_with_zero);
-			printf ("\n");
+		if (status & MONO_RELATIONS_EVALUATION_COMPLETED) {
+			if (print_or) printf ("|");
+			printf ("EVALUATION_COMPLETED");
+			print_or = TRUE;
 		}
-		if (relations->relation_with_one != MONO_ANY_RELATION) {
-			printf ("relation_with_one: ");
-			print_relation (relations->relation_with_one);
-			printf ("\n");
+		if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING) {
+			if (print_or) printf ("|");
+			printf ("RECURSIVELY_ASCENDING");
+			print_or = TRUE;
 		}
-		if (significantRelations > 0) {
-			printf ("relations_with_variables (%d significant)\n", significantRelations);
-			for (i = 0; i < n; i++) {
-				if (relations->relations_with_variables [i] != MONO_ANY_RELATION) {
-					printf ("relation with variable %d: ", i);
-					print_relation (relations->relations_with_variables [i]);
-					printf ("\n");
-				}
-			}
+		if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING) {
+			if (print_or) printf ("|");
+			printf ("RECURSIVELY_DESCENDING");
+			print_or = TRUE;
 		}
+		if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE) {
+			if (print_or) printf ("|");
+			printf ("RECURSIVELY_INDEFINITE");
+			print_or = TRUE;
+		}
+		printf (")");
 	}
 }
 
+
 static void
-print_all_variable_relations (MonoVariableRelationsEvaluationArea *evaluation_area) {
-	int i;
-	printf ("relations in evaluation area:\n");
-	for (i = 0; i < evaluation_area->cfg->num_varinfo; i++) {
-		print_variable_relations (&(evaluation_area->variable_relations [i]), i, evaluation_area->cfg->num_varinfo);
+print_evaluation_context_ranges (MonoRelationsEvaluationRanges *ranges) {
+	printf ("(ranges: zero [%d,%d], variable [%d,%d])", ranges->zero.lower, ranges->zero.upper, ranges->variable.lower, ranges->variable.upper);
+}
+
+static void
+print_evaluation_context (MonoRelationsEvaluationContext *context) {
+	printf ("Context status: ");
+	print_evaluation_context_status (context->status);
+	if (context->status & (MONO_RELATIONS_EVALUATION_IN_PROGRESS|MONO_RELATIONS_EVALUATION_COMPLETED)) {
+		print_evaluation_context_ranges (&(context->ranges));
 	}
+	printf ("\n");
 }
 
+#if 0
+static void
+print_evaluation_area (MonoVariableRelationsEvaluationArea *area) {
+	int i;
+	printf ("Dump of evaluation area (%d variables):\n", area->cfg->num_varinfo);
+	for (i = 0; i < area->cfg->num_varinfo; i++) {
+		printf ("Variable %d: ", i);
+		print_evaluation_context (&(area->contexts [i]));
+		print_summarized_value_relation_chain (&(area->relations [i]));
+	}
+}
 
-static MonoValueRelation
-relation_for_sum_of_variable_and_constant (
-		MonoValueRelation variable_relation, MonoValueRelation constant_relation_with_zero) {
-	switch (variable_relation) {
-	case MONO_EQ_RELATION:
-		return constant_relation_with_zero;
-	case MONO_GE_RELATION:
-		if (constant_relation_with_zero & MONO_LT_RELATION) {
-			return MONO_ANY_RELATION;
-		} else {
-			return constant_relation_with_zero;
-		}
-	case MONO_LE_RELATION:
-		if (constant_relation_with_zero & MONO_GT_RELATION) {
-			return MONO_ANY_RELATION;
-		} else {
-			return constant_relation_with_zero;
-		}
-	case MONO_GT_RELATION:
-		if (constant_relation_with_zero & MONO_LT_RELATION) {
-			return MONO_ANY_RELATION;
-		} else {
-			return MONO_GT_RELATION;
-		}
-	case MONO_LT_RELATION:
-		if (constant_relation_with_zero & MONO_GT_RELATION) {
-			return MONO_ANY_RELATION;
-		} else {
-			return MONO_LE_RELATION;
-		}
-	default:
-		g_assert_not_reached ();
-		return MONO_ANY_RELATION;
+static void
+print_evaluation_area_contexts (MonoVariableRelationsEvaluationArea *area) {
+	int i;
+	printf ("Dump of evaluation area contexts (%d variables):\n", area->cfg->num_varinfo);
+	for (i = 0; i < area->cfg->num_varinfo; i++) {
+		printf ("Variable %d: ", i);
+		print_evaluation_context (&(area->contexts [i]));
 	}
 }
+#endif
 
+/**
+ * Given a MonoInst, if it is a store to a variable return the MonoInst that
+ * represents the stored value.
+ * If anything goes wrong, return NULL.
+ * store: the MonoInst that should be a store
+ * expected_variable_index: the variable where the value should be stored
+ * return: either the stored value, or NULL
+ */
 static MonoInst *
-get_variable_value_from_ssa_store (MonoInst *store, int expected_variable_index) {
+get_variable_value_from_store_instruction (MonoInst *store, int expected_variable_index) {
 	switch (store->opcode) {
 	case CEE_STIND_REF:
 	case CEE_STIND_I:
@@ -235,12 +227,12 @@ get_variable_value_from_ssa_store (MonoInst *store, int expected_variable_index)
 	case CEE_STIND_R4:
 	case CEE_STIND_R8:
 		if (TRACE_ABC_REMOVAL) {
-			printf ("Store instruction found...\n");
+			printf ("[store instruction found]");
 		}
 		if (store->inst_left->opcode == OP_LOCAL) {
 			int variable_index = store->inst_left->inst_c0;
 			if (TRACE_ABC_REMOVAL) {
-				printf ("Value put in local %d (expected %d)\n", variable_index, expected_variable_index);
+				printf ("[value put in local %d (expected %d)]", variable_index, expected_variable_index);
 			}
 			if (variable_index == expected_variable_index) {
 				return store->inst_right;
@@ -258,104 +250,87 @@ get_variable_value_from_ssa_store (MonoInst *store, int expected_variable_index)
 	}
 }
 
+/**
+ * Given a MonoInst representing a value, store it in "summarized" form.
+ * result: the "summarized" value
+ */
 static void
 summarize_value (MonoInst *value, MonoSummarizedValue *result) {
 	switch (value->opcode) {
 	case OP_ICONST:
-		result->relation_with_zero = RELATION_BETWEEN_VALUES (value->inst_c0, 0);
-		result->relation_with_one = RELATION_BETWEEN_VALUES (abs (value->inst_c0), 1);
-		result->relation_with_value = MONO_EQ_RELATION;
-		result->value_type = MONO_CONSTANT_SUMMARIZED_VALUE;
-		result->value.constant = value->inst_c0;
+		result->type = MONO_CONSTANT_SUMMARIZED_VALUE;
+		result->value.constant.value = value->inst_c0;
 		break;
 	case OP_LOCAL:
 	case OP_ARG:
-		result->relation_with_zero = MONO_ANY_RELATION;
-		result->relation_with_one = MONO_ANY_RELATION;
-		result->relation_with_value = MONO_EQ_RELATION;
-		result->value_type = MONO_VARIABLE_SUMMARIZED_VALUE;
-		result->value.variable = value->inst_c0;
-		break;
-	case CEE_LDIND_I4: {
-		if ((value->inst_left->opcode == OP_LOCAL) || (value->inst_left->opcode == OP_ARG)) {
-			summarize_value (value->inst_left, result);
-		} else {
-			MAKE_VALUE_ANY (result);
-		}
+		result->type = MONO_VARIABLE_SUMMARIZED_VALUE;
+		result->value.variable.variable = value->inst_c0;
+		result->value.variable.delta = 0;
 		break;
-	}
+	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_REF:
 		if ((value->inst_left->opcode == OP_LOCAL) || (value->inst_left->opcode == OP_ARG)) {
 			summarize_value (value->inst_left, result);
 		} else {
-			MAKE_VALUE_ANY (result);
+			MAKE_VALUE_ANY (*result);
 		}
 		break;
-	case CEE_ADD:
-	case CEE_SUB: {
+	case CEE_ADD: {
 		MonoSummarizedValue left_value;
 		MonoSummarizedValue right_value;
 		summarize_value (value->inst_left, &left_value);
 		summarize_value (value->inst_right, &right_value);
 
-		if (IS_SUMMARIZED_VALUE_VARIABLE (left_value)) {
-			if (IS_SUMMARIZED_VALUE_CONSTANT (right_value)&& (right_value.value.constant   = 1)) {
-				MonoValueRelation constant_relation_with_zero = right_value.relation_with_zero;
-				if (value->opcode == CEE_SUB) {
-					constant_relation_with_zero = MONO_SYMMETRIC_RELATION (constant_relation_with_zero);
-				}
-				result->relation_with_value = relation_for_sum_of_variable_and_constant (
-					left_value.relation_with_value, constant_relation_with_zero);
-				if (result->relation_with_value != MONO_ANY_RELATION) {
-					result->relation_with_zero = MONO_ANY_RELATION;
-					result->relation_with_one = MONO_ANY_RELATION;
-					result->value_type = MONO_VARIABLE_SUMMARIZED_VALUE;
-					result->value.variable = left_value.value.variable;
-				} else {
-					MAKE_VALUE_ANY (result);
-				}
+		if (left_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
+			if (right_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) {
+				result->type = MONO_VARIABLE_SUMMARIZED_VALUE;
+				result->value.variable.variable = left_value.value.variable.variable;
+				result->value.variable.delta = left_value.value.variable.delta + right_value.value.constant.value;
 			} else {
-				MAKE_VALUE_ANY (result);
+				MAKE_VALUE_ANY (*result);
 			}
-		} else if (IS_SUMMARIZED_VALUE_VARIABLE (right_value)) {
-			if (IS_SUMMARIZED_VALUE_CONSTANT (left_value)&& (left_value.value.constant == 1)) {
-				MonoValueRelation constant_relation_with_zero = left_value.relation_with_zero;
-				if (value->opcode == CEE_SUB) {
-					constant_relation_with_zero = MONO_SYMMETRIC_RELATION (constant_relation_with_zero);
-				}
-				result->relation_with_value = relation_for_sum_of_variable_and_constant (
-					right_value.relation_with_value, constant_relation_with_zero);
-				if (result->relation_with_value != MONO_ANY_RELATION) {
-					result->relation_with_zero = MONO_ANY_RELATION;
-					result->relation_with_one = MONO_ANY_RELATION;
-					result->value_type = MONO_VARIABLE_SUMMARIZED_VALUE;
-					result->value.variable = right_value.value.variable;
-				} else {
-					MAKE_VALUE_ANY (result);
-				}
+		} else if (right_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
+			if (left_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) {
+				result->type = MONO_VARIABLE_SUMMARIZED_VALUE;
+				result->value.variable.variable = right_value.value.variable.variable;
+				result->value.variable.delta = left_value.value.constant.value + right_value.value.variable.delta;
 			} else {
-				MAKE_VALUE_ANY (result);
+				MAKE_VALUE_ANY (*result);
 			}
-		} else if (IS_SUMMARIZED_VALUE_CONSTANT (right_value)&& IS_SUMMARIZED_VALUE_CONSTANT (left_value)) {
+		} else if ((right_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) && (left_value.type == MONO_CONSTANT_SUMMARIZED_VALUE)) {
 			/* This should not happen if constant folding has been done */
-			if (right_value.relation_with_value == MONO_EQ_RELATION && left_value.relation_with_value == MONO_EQ_RELATION) {
-				int constant;
-				if (value->opcode == CEE_ADD) {
-					constant = right_value.value.constant + left_value.value.constant;
-				}
-				else {
-					constant = right_value.value.constant - left_value.value.constant;
-				}
-				result->relation_with_zero = RELATION_BETWEEN_VALUES (constant, 0);
-				result->relation_with_one = RELATION_BETWEEN_VALUES (abs (constant), 1);
-				result->relation_with_value = MONO_EQ_RELATION;
-				result->value_type = MONO_CONSTANT_SUMMARIZED_VALUE;
-				result->value.constant = constant;
+			result->type = MONO_CONSTANT_SUMMARIZED_VALUE;
+			result->value.constant.value = left_value.value.constant.value + right_value.value.constant.value;
+		} else {
+			MAKE_VALUE_ANY (*result);
+		}
+		break;
+	}
+	case CEE_SUB: {
+		MonoSummarizedValue left_value;
+		MonoSummarizedValue right_value;
+		summarize_value (value->inst_left, &left_value);
+		summarize_value (value->inst_right, &right_value);
+
+		if (left_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
+			if (right_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) {
+				result->type = MONO_VARIABLE_SUMMARIZED_VALUE;
+				result->value.variable.variable = left_value.value.variable.variable;
+				result->value.variable.delta = left_value.value.variable.delta - right_value.value.constant.value;
 			} else {
-				MAKE_VALUE_ANY (result);
+				MAKE_VALUE_ANY (*result);
 			}
+		} else if ((right_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) && (left_value.type == MONO_CONSTANT_SUMMARIZED_VALUE)) {
+			/* This should not happen if constant folding has been done */
+			result->type = MONO_CONSTANT_SUMMARIZED_VALUE;
+			result->value.constant.value = left_value.value.constant.value - right_value.value.constant.value;
 		} else {
-			MAKE_VALUE_ANY (result);
+			MAKE_VALUE_ANY (*result);
 		}
 		break;
 	}
@@ -366,14 +341,12 @@ summarize_value (MonoInst *value, MonoSummarizedValue *result) {
 		summarize_value (value->inst_left, result);
 		break;
 	case OP_PHI:
-		result->relation_with_zero = MONO_ANY_RELATION;
-		result->relation_with_one = MONO_ANY_RELATION;
-		result->relation_with_value = MONO_EQ_RELATION;
-		result->value_type = MONO_PHI_SUMMARIZED_VALUE;
-		result->value.phi_variables = value->inst_phi_args;
+		result->type = MONO_PHI_SUMMARIZED_VALUE;
+		result->value.phi.number_of_alternatives = *(value->inst_phi_args);
+		result->value.phi.phi_alternatives = value->inst_phi_args + 1;
 		break;
 	default:
-		MAKE_VALUE_ANY (result);
+		MAKE_VALUE_ANY (*result);
 	}
 }
 
@@ -397,652 +370,754 @@ get_relation_from_branch_instruction (int opcode) {
 	case CEE_BNE_UN:
 		return MONO_NE_RELATION;
 	default:
-		g_assert_not_reached ();
 		return MONO_ANY_RELATION;
 	}
 }
 
-static int
-contains_array_access (MonoInst *inst) {
-	if (inst->opcode == CEE_LDELEMA) { /* Handle OP_LDELEMA2D, too */
-		return 1;
-	}
-
-	if (mono_burg_arity [inst->opcode]) {
-		if (contains_array_access (inst->inst_left)) {
-			return 1;
-		}
-		if (mono_burg_arity [inst->opcode] > 1) {
-			return contains_array_access (inst->inst_right);
-		}
-	}
-	return 0;
-}
-
+/**
+ * Given a BB, find its entry condition and put its relations in a
+ * "MonoAdditionalVariableRelationsForBB" structure.
+ * bb: the BB
+ * relations: the resulting relations (entry condition of the given BB)
+ */
 static void
-analyze_block (MonoBasicBlock *bb, MonoVariableRelationsEvaluationArea *evaluation_area) {
-	MonoSummarizedBasicBlock *b = &(evaluation_area->blocks [bb->dfn]);
-	MonoInst *current_inst = bb->code;
-	MonoInst *last_inst = NULL;
-	int inst_index = 0;
+get_relations_from_previous_bb (MonoBasicBlock *bb, MonoAdditionalVariableRelationsForBB *relations) {
+	MonoBasicBlock *in_bb;
+	MonoInst *branch;
+	MonoValueRelation branch_relation;
+	MonoValueRelation symmetric_relation;
 	
-	if (TRACE_ABC_REMOVAL) {
-		printf ("Analyzing block %d [dfn %d]\n", bb->block_num, bb->dfn);
-	}
+	INITIALIZE_VALUE_RELATION (&(relations->relation1.relation));
+	relations->relation1.relation.relation_is_static_definition = FALSE;
+	relations->relation1.insertion_point = NULL;
+	relations->relation1.variable = -1;
+	INITIALIZE_VALUE_RELATION (&(relations->relation2.relation));
+	relations->relation2.relation.relation_is_static_definition = FALSE;
+	relations->relation2.insertion_point = NULL;
+	relations->relation2.variable = -1;
 	
-	g_assert (bb->dfn < evaluation_area->cfg->num_bblocks);
-	b->has_array_access_instructions = 0;
-	b->block = bb;
 	
-	while (current_inst != NULL) {
-		if (TRACE_ABC_REMOVAL) {
-			printf ("Analyzing instruction %d\n", inst_index);
-			inst_index++;
-		}
-		
-		if (contains_array_access (current_inst)) {
-			b->has_array_access_instructions = 1;
-		}
-		
-		if (current_inst->next == NULL) {
-			last_inst = current_inst;
-		}
-		current_inst = current_inst->next;
-	}
-	
-	if (last_inst != NULL) {
-		switch (last_inst->opcode) {
-		case CEE_BEQ:
-		case CEE_BLT:
-		case CEE_BLE:
-		case CEE_BGT:
-		case CEE_BGE:
-		case CEE_BNE_UN:
-		case CEE_BLT_UN:
-		case CEE_BLE_UN:
-		case CEE_BGT_UN:
-		case CEE_BGE_UN:
-			if (last_inst->inst_left->opcode == OP_COMPARE) {
-				int number_of_variables = 0;
-				int current_variable = 0;
-				
-				MonoSummarizedValue left_value;
-				MonoSummarizedValue right_value;
-				MonoValueRelation relation = get_relation_from_branch_instruction (last_inst->opcode);
-				MonoValueRelation symmetric_relation = MONO_SYMMETRIC_RELATION (relation);
-				summarize_value (last_inst->inst_left->inst_left, &left_value);
-				summarize_value (last_inst->inst_left->inst_right, &right_value);
-				/* It is actually possible to handle some more case... */
-				if ((left_value.relation_with_value == MONO_EQ_RELATION) &&
-					(right_value.relation_with_value == MONO_EQ_RELATION)) {
-					if (left_value.value_type == MONO_VARIABLE_SUMMARIZED_VALUE)number_of_variables++;
-					if (right_value.value_type == MONO_VARIABLE_SUMMARIZED_VALUE)number_of_variables++;
-					if (number_of_variables > 0) {
-						MonoBranchData *branch_true;
-						MonoBranchData *branch_false;
+	if (bb->in_count == 1) { /* Should write the code to "sum" conditions... */
+		in_bb = bb->in_bb [0];
+		branch = in_bb->last_ins;
+		if (branch == NULL) return;
+		branch_relation = get_relation_from_branch_instruction (branch->opcode);
+		if ((branch_relation != MONO_ANY_RELATION) && (branch->inst_left->opcode == OP_COMPARE)) {
+			MonoSummarizedValue left_value;
+			MonoSummarizedValue right_value;
+			gboolean code_path;
 
-						b->number_of_branches = 2;
-						b->branches = (MonoBranchData*) mono_mempool_alloc (
-							evaluation_area->pool, sizeof (MonoBranchData) * 2);
-						branch_true = &(b->branches [0]);
-						branch_true->destination_block = last_inst->inst_true_bb;
-						branch_true->number_of_conditions = number_of_variables;
-						branch_true->conditions = (MonoBranchCondition*)
-							mono_mempool_alloc (evaluation_area->pool, sizeof (MonoBranchCondition) * number_of_variables);
-						branch_false = &(b->branches [1]);
-						branch_false->destination_block = last_inst->inst_false_bb;
-						branch_false->number_of_conditions = number_of_variables;
-						branch_false->conditions = (MonoBranchCondition*)
-							mono_mempool_alloc (evaluation_area->pool, sizeof (MonoBranchCondition) * number_of_variables);
-						if (left_value.value_type == MONO_VARIABLE_SUMMARIZED_VALUE) {
-							MonoBranchCondition *condition_true = &(branch_true->conditions [current_variable]);
-							MonoBranchCondition *condition_false;
+			if (branch->inst_true_bb == bb) {
+				code_path = TRUE;
+			} else if (branch->inst_false_bb == bb) {
+				code_path = FALSE;
+			} else {
+				code_path = TRUE;
+				g_assert_not_reached ();
+			}
 
-							condition_true->variable = left_value.value.variable;
-							condition_true->value = right_value;
-							condition_true->value.relation_with_zero = MONO_ANY_RELATION;
-							condition_true->value.relation_with_one = MONO_ANY_RELATION;
-							condition_true->value.relation_with_value = relation;
-							condition_false = &(branch_false->conditions [current_variable]);
-							condition_false->variable = left_value.value.variable;
-							condition_false->value = right_value;
-							condition_false->value.relation_with_zero = MONO_ANY_RELATION;
-							condition_false->value.relation_with_one = MONO_ANY_RELATION;
-							condition_false->value.relation_with_value = MONO_NEGATED_RELATION (relation);
-							current_variable++;
-						}
-						if (right_value.value_type == MONO_VARIABLE_SUMMARIZED_VALUE) {
-							MonoBranchCondition *condition_true = &(branch_true->conditions [current_variable]);
-							MonoBranchCondition *condition_false;
+			if (!code_path) {
+				branch_relation = MONO_NEGATED_RELATION (branch_relation);
+			}
+			symmetric_relation = MONO_SYMMETRIC_RELATION (branch_relation);
 
-							condition_true->variable = right_value.value.variable;
-							condition_true->value = left_value;
-							condition_true->value.relation_with_zero = MONO_ANY_RELATION;
-							condition_true->value.relation_with_one = MONO_ANY_RELATION;
-							condition_true->value.relation_with_value = symmetric_relation;
-							condition_false = &(branch_false->conditions [current_variable]);
-							condition_false->variable = right_value.value.variable;
-							condition_false->value = left_value;
-							condition_false->value.relation_with_zero = MONO_ANY_RELATION;
-							condition_false->value.relation_with_one = MONO_ANY_RELATION;
-							condition_false->value.relation_with_value = MONO_NEGATED_RELATION (symmetric_relation);
-						}
-					} else {
-						b->number_of_branches = 0;
-						b->branches = NULL;
-					}
+			summarize_value (branch->inst_left->inst_left, &left_value);
+			summarize_value (branch->inst_left->inst_right, &right_value);
+
+			if ((left_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) && ((right_value.type == MONO_VARIABLE_SUMMARIZED_VALUE)||(right_value.type == MONO_CONSTANT_SUMMARIZED_VALUE))) {
+				relations->relation1.variable = left_value.value.variable.variable;
+				relations->relation1.relation.relation = branch_relation;
+				relations->relation1.relation.related_value = right_value;
+				if (right_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) {
+					relations->relation1.relation.related_value.value.constant.value -= left_value.value.variable.delta;
 				} else {
-					b->number_of_branches = 0;
-					b->branches = NULL;
+					relations->relation1.relation.related_value.value.variable.delta -= left_value.value.variable.delta;
+				}
+			}
+			if ((right_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) && ((left_value.type == MONO_VARIABLE_SUMMARIZED_VALUE)||(left_value.type == MONO_CONSTANT_SUMMARIZED_VALUE))) {
+				relations->relation2.variable = right_value.value.variable.variable;
+				relations->relation2.relation.relation = symmetric_relation;
+				relations->relation2.relation.related_value = left_value;
+				if (left_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) {
+					relations->relation2.relation.related_value.value.constant.value -= right_value.value.variable.delta;
+				} else {
+					relations->relation2.relation.related_value.value.variable.delta -= right_value.value.variable.delta;
 				}
-			} else {
-				b->number_of_branches = 0;
-				b->branches = NULL;
 			}
-			break;
-		case CEE_SWITCH:
-			/* Should handle switches... */
-			/* switch_operand = last_inst->inst_right; */
-			/* number_of_cases = GPOINTER_TO_INT (last_inst->klass); */
-			/* cases = last_inst->inst_many_bb; */
-			b->number_of_branches = 0;
-			b->branches = NULL;
-			break;
-		default:
-			b->number_of_branches = 0;
-			b->branches = NULL;
 		}
-	} else {
-		b->number_of_branches = 0;
-		b->branches = NULL;
 	}
+}
 
-	if (TRACE_ABC_REMOVAL) {
-		print_summarized_block (b);
+
+/**
+ * Add the given relations to the evaluation area.
+ * area: the evaluation area
+ * change: the relations that must be added
+ */
+static void
+apply_change_to_evaluation_area (MonoVariableRelationsEvaluationArea *area, MonoAdditionalVariableRelation *change) {
+	MonoSummarizedValueRelation *base_relation;
+	
+	if (change->relation.relation != MONO_ANY_RELATION) {
+		base_relation = &(area->relations [change->variable]);
+		while ((base_relation->next != NULL) && (base_relation->next->relation_is_static_definition)) {
+			base_relation = base_relation->next;
+		}
+		change->insertion_point = base_relation;
+		change->relation.next = base_relation->next;
+		base_relation->next = &(change->relation);
+	}
+}
+
+/**
+ * Remove the given relation from the evaluation area.
+ * change: the relation that must be removed
+ */
+static void
+remove_change_from_evaluation_area (MonoAdditionalVariableRelation *change) {
+	if (change->insertion_point != NULL) {
+		change->insertion_point->next = change->relation.next;
+		change->relation.next = NULL;
 	}
 }
 
-#define SET_VARIABLE_RELATIONS(vr, relation, n)do {\
-	(vr)->relation_with_zero = (relation);\
-	(vr)->relation_with_one = (relation);\
-	memset ((vr)->relations_with_variables,(relation),(n));\
-} while (0);
 
-#define COMBINE_VARIABLE_RELATIONS(operator, vr, related_vr, n)do {\
-	int i;\
-	operator ((vr)->relation_with_zero, (related_vr)->relation_with_zero);\
-	operator ((vr)->relation_with_one, (related_vr)->relation_with_one);\
-	for (i = 0; i < (n); i++) {\
-		operator ((vr)->relations_with_variables [i], (related_vr)->relations_with_variables [i]);\
-	}\
-} while (0);
+static void
+clean_contexts (MonoRelationsEvaluationContext *contexts, int number) {
+	int i;
+	for (i = 0; i < number; i++) {
+		contexts [i].status = MONO_RELATIONS_EVALUATION_NOT_STARTED;
+	}
+}
 
-#define RELATION_ASSIGNMENT(destination,source) (destination)=(source)
-#define RELATION_UNION(destination,source) (destination)|=(source)
-#define RELATION_INTERSECTION(destination,source) (destination)&=(source)
 
+/**
+ * Perform the intersection of a range and a constant value (taking into
+ * account the relation that the value has with the range).
+ * range: the range that will be intersected with the value
+ * value: the value that will be intersected with the range
+ * relation: the relation between the range and the value
+ */
+static void
+intersect_value( MonoRelationsEvaluationRange *range, int value, MonoValueRelation relation ) {
+	switch (relation) {
+	case MONO_NO_RELATION:
+		MONO_MAKE_RELATIONS_EVALUATION_RANGE_IMPOSSIBLE (*range);
+		break;
+	case MONO_ANY_RELATION:
+		break;
+	case MONO_EQ_RELATION:
+		MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, value);
+		MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, value);
+		break;
+	case MONO_NE_RELATION: {
+		/* IMPROVEMENT Figure this out! (ignoring it is safe anyway) */
+		break;
+	}
+	case MONO_LT_RELATION:
+		MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (value));
+		break;
+	case MONO_LE_RELATION:
+		MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, value);
+		break;
+	case MONO_GT_RELATION:
+		MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (value));
+		break;
+	case MONO_GE_RELATION:
+		MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, value);
+		break;
+	default:
+		g_assert_not_reached();
+	}
+}
 
 
+/**
+ * Perform the intersection of two pairs of ranges (taking into account the
+ * relation between the ranges and a given delta).
+ * ranges: the ranges that will be intersected
+ * other_ranges the other ranges that will be intersected
+ * delta: the delta between the pairs of ranges
+ * relation: the relation between the pairs of ranges
+ */
 static void
-evaluate_variable_relations (gssize variable, MonoVariableRelationsEvaluationArea *evaluation_area, MonoRelationsEvaluationContext *father_context) {
-	MonoVariableRelations *relations = &(evaluation_area->variable_relations [variable]);
-	MonoRelationsEvaluationContext context;
-	if (TRACE_ABC_REMOVAL) {
-		printf ("Applying definition of variable %d\n", variable);
+intersect_ranges( MonoRelationsEvaluationRanges *ranges, MonoRelationsEvaluationRanges *other_ranges, int delta, MonoValueRelation relation ) {
+	if (delta == 0) {
+		switch (relation) {
+		case MONO_NO_RELATION:
+			MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (*ranges);
+			break;
+		case MONO_ANY_RELATION:
+			break;
+		case MONO_EQ_RELATION:
+			MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (*ranges, *other_ranges);
+			break;
+		case MONO_NE_RELATION: {
+			/* FIXME Figure this out! (ignoring it is safe anyway) */
+			break;
+		}
+		case MONO_LT_RELATION:
+			MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->zero.upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->zero.upper));
+			MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->variable.upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->variable.upper));
+			break;
+		case MONO_LE_RELATION:
+			MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->zero.upper, other_ranges->zero.upper);
+			MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->variable.upper, other_ranges->variable.upper);
+			break;
+		case MONO_GT_RELATION:
+			MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->zero.lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->zero.lower));
+			MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->variable.lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->variable.lower));
+			break;
+		case MONO_GE_RELATION:
+			MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->zero.lower, other_ranges->zero.lower);
+			MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->variable.lower, other_ranges->variable.lower);
+			break;
+		default:
+			g_assert_not_reached();
+		}
+	} else {
+		MonoRelationsEvaluationRanges translated_ranges = *other_ranges;
+		MONO_ADD_DELTA_SAFELY_TO_RANGES (translated_ranges, delta);
+		intersect_ranges( ranges, &translated_ranges, FALSE, relation );
 	}
-	context.father_context = father_context;
-	context.variable = variable;
-	switch (relations->evaluation_step) {
+}
+
+/**
+ * Recursive method that traverses the relation graph to evaluate the
+ * relation between two variables.
+ * At the end of the execution, the resulting ranges are in the context of
+ * the "starting" variable.
+ * area: the current evaluation area (it contains the relation graph and
+ *       memory for all the evaluation contexts is already allocated)
+ * variable: starting variable (the value ranges in its context are the result
+ *           of the execution of this procedure)
+ * target_variable: the variable with respect to which the starting variable
+ *                  is evaluated (tipically the starting variable is the index
+ *                  and the target one is the array (which means its length))
+ * father_context: the previous evaluation context in recursive invocations
+ *                 (or NULL for the first invocation)
+ */
+static void
+evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *area, int variable, int target_variable, MonoRelationsEvaluationContext *father_context) {
+	MonoRelationsEvaluationContext *context = &(area->contexts [variable]);
+	
+	// First of all, we check the evaluation status
+	// (what must be done is *very* different in each case)
+	switch (context->status) {
 	case MONO_RELATIONS_EVALUATION_NOT_STARTED: {
-		MonoSummarizedValue *value = &(evaluation_area->variable_definitions [variable]);
-		relations->evaluation_step = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
+		MonoSummarizedValueRelation *relation = &(area->relations [variable]);
+		
 		if (TRACE_ABC_REMOVAL) {
-			printf ("Current step is MONO_RELATIONS_EVALUATION_NOT_STARTED, summarized value is:\n");
-			print_summarized_value (value);
+			printf ("Evaluating varible %d (target variable %d)\n", variable, target_variable);
+			print_summarized_value_relation (relation);
+			printf ("\n");
 		}
-		switch (value->value_type) {
-		case MONO_CONSTANT_SUMMARIZED_VALUE:
-			if (value->relation_with_value == MONO_EQ_RELATION) {
-				relations->relation_with_zero &= RELATION_BETWEEN_VALUES (value->value.constant, 0);
-				relations->relation_with_one &= RELATION_BETWEEN_VALUES (abs (value->value.constant), 1);
-			}
-			/* Other cases should not happen... */
-			break;
-		case MONO_VARIABLE_SUMMARIZED_VALUE: {
-			gssize related_variable = value->value.variable;
-			relations->relations_with_variables [related_variable] = value->relation_with_value;
-			evaluate_variable_relations (related_variable, evaluation_area, &context);
-			if (value->relation_with_value == MONO_EQ_RELATION) {
-				COMBINE_VARIABLE_RELATIONS (RELATION_INTERSECTION, relations,
-					&(evaluation_area->variable_relations [related_variable]), evaluation_area->cfg->num_varinfo);
+		
+		// We properly inizialize the context
+		context->status = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
+		context->father = father_context;
+		MONO_MAKE_RELATIONS_EVALUATION_RANGES_WEAK (context->ranges);
+		
+		// If we have found the target variable, we can set the range
+		// related to it in the context to "equal" (which is [0,0])
+		if (variable == target_variable) {
+			if (TRACE_ABC_REMOVAL) {
+				printf ("Target variable reached (%d), continuing to evaluate relations with constants\n", variable);
 			}
-			/* Other cases should be handled... */
-			break;
+			context->ranges.variable.lower = 0;
+			context->ranges.variable.upper = 0;
 		}
-		case MONO_PHI_SUMMARIZED_VALUE:
-			if (value->relation_with_value == MONO_EQ_RELATION) {
+		
+		// Examine all relations for this variable (scan the list)
+		// The contribute of each relation will be intersected (logical and)
+		while (relation != NULL) {
+			context->current_relation = relation;
+			
+			if (TRACE_ABC_REMOVAL) {
+				printf ("Processing (%d): ", variable);
+				print_summarized_value_relation (relation);
+				printf ("\n");
+			}
+			
+			// We decie what to do according the the type of the related value
+			switch (relation->related_value.type) {
+			case MONO_ANY_SUMMARIZED_VALUE:
+				// No added information, skip it
+				break;
+			case MONO_CONSTANT_SUMMARIZED_VALUE:
+				// Intersect range with constant (taking into account the relation)
+				intersect_value (&(context->ranges.zero), relation->related_value.value.constant.value, relation->relation);
+				break;
+			case MONO_VARIABLE_SUMMARIZED_VALUE:
+				// Generally, evaluate related variable and intersect ranges.
+				// However, some check is necessary...
+				
+				// If the relation is "ANY", nothing to do (no added information)
+				if (relation->relation != MONO_ANY_RELATION) {
+					gssize related_variable = relation->related_value.value.variable.variable;
+					MonoRelationsEvaluationContext *related_context = &(area->contexts [related_variable]);
+					
+					// The second condition in the "or" avoids messing with "back edges" in the graph traversal
+					// (they are simply ignored instead of triggering the handling of recursion)
+					if ( (related_context->status == MONO_RELATIONS_EVALUATION_NOT_STARTED) || !
+							((related_context->current_relation->related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) &&
+							(related_context->current_relation->related_value.value.variable.variable == variable))) {
+						// Evaluate the related variable
+						evaluate_relation_with_target_variable (area, related_variable, target_variable, context);
+						
+						// Check if we are part of a recursive loop
+						if (context->status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
+							if (TRACE_ABC_REMOVAL) {
+								printf ("Recursivity detected for varible %d (target variable %d), status ", variable, target_variable);
+								print_evaluation_context_status (context->status);
+							}
+							
+							// If we are, check if the evaluation of the related variable is complete
+							if (related_context->status == MONO_RELATIONS_EVALUATION_COMPLETED) {
+								// If it is complete, we are part of a recursive definition.
+								// Since it is a *definition* (and definitions are evaluated *before*
+								// conditions because they are first in the list), intersection is not
+								// strictly necessary, we simply copy the ranges and apply the delta
+								context->ranges = related_context->ranges;
+								MONO_ADD_DELTA_SAFELY_TO_RANGES (context->ranges, relation->related_value.value.variable.delta);
+								context->status = MONO_RELATIONS_EVALUATION_COMPLETED;
+								if (TRACE_ABC_REMOVAL) {
+									printf (", ranges already computed, result: \n");
+									print_evaluation_context_ranges (&(context->ranges));
+									printf (" (delta is %d)\n", relation->related_value.value.variable.delta);
+								}
+							} else {
+								// If it is not complete, do nothing (we do not have enough information)
+								if (TRACE_ABC_REMOVAL) {
+									printf (", ranges not computed\n");
+								}
+							}
+						} else {
+							// If we are not (the common case) intersect the result
+							intersect_ranges( &(context->ranges), &(related_context->ranges), relation->related_value.value.variable.delta, relation->relation );
+						}
+					} else {
+						if (TRACE_ABC_REMOVAL) {
+							printf ("Relation is a back-edge in this traversal, skipping\n");
+						}
+					}
+				}
+				break;
+			case MONO_PHI_SUMMARIZED_VALUE: {
+				// We must compute all PHI alternatives, combining the results (with a union, which is a logical "or"),
+				// and intersect this result with the ranges in the context; we must also take into account recursions
+				// (with loops that can be ascending, descending, or indefinite)
+				MonoRelationsEvaluationRanges phi_ranges;
 				int phi;
-				MonoVariableRelations *phi_union = (MonoVariableRelations*) alloca (sizeof (MonoVariableRelations));
-				phi_union->relations_with_variables = (unsigned char*) alloca (evaluation_area->cfg->num_varinfo);
-				SET_VARIABLE_RELATIONS (phi_union, MONO_NO_RELATION, evaluation_area->cfg->num_varinfo);
-				for (phi = 0; phi < *(value->value.phi_variables); phi++) {
-					gssize related_variable = value->value.phi_variables [phi+1];
-					evaluate_variable_relations (related_variable, evaluation_area, &context);
-					COMBINE_VARIABLE_RELATIONS (RELATION_UNION, phi_union,
-						&(evaluation_area->variable_relations [related_variable]), evaluation_area->cfg->num_varinfo);
+				gboolean is_ascending = FALSE;
+				gboolean is_descending = FALSE;
+				
+				MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (phi_ranges);
+				for (phi = 0; phi < relation->related_value.value.phi.number_of_alternatives; phi++) {
+					int phi_alternative = relation->related_value.value.phi.phi_alternatives [phi];
+					evaluate_relation_with_target_variable (area, phi_alternative, target_variable, context);
+					
+					// This means we are part of a recursive loop
+					if (context->status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
+						if (TRACE_ABC_REMOVAL) {
+							printf ("Recursivity detected for varible %d (target variable %d), status ", variable, target_variable);
+							print_evaluation_context_status (context->status);
+							printf ("\n");
+						}
+						if (context->status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING) {
+							is_ascending = TRUE;
+						}
+						if (context->status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING) {
+							is_descending = TRUE;
+						}
+						if (context->status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE) {
+							is_ascending = TRUE;
+							is_descending = TRUE;
+						}
+						
+						// Clear "recursivity" bits in the status (recursion has been handled)
+						context->status = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
+					} else {
+						MONO_RELATIONS_EVALUATION_RANGES_UNION (phi_ranges, area->contexts [phi_alternative].ranges);
+					}
 				}
-				if (TRACE_ABC_REMOVAL) {
-					printf ("Resulting phi_union is:\n");
-					print_variable_relations (phi_union, variable, evaluation_area->cfg->num_varinfo);
+				
+				// Apply the effects of all recursive loops
+				if (is_ascending) {
+					phi_ranges.zero.upper = INT_MAX;
+					phi_ranges.variable.upper = INT_MAX;
+				}
+				if (is_descending) {
+					phi_ranges.zero.lower = INT_MIN;
+					phi_ranges.variable.lower = INT_MIN;
 				}
-				COMBINE_VARIABLE_RELATIONS (RELATION_INTERSECTION, relations,
-					phi_union, evaluation_area->cfg->num_varinfo);
+				
+				// Intersect final result
+				MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (context->ranges, phi_ranges);
+				break;
 			}
-			/* Other cases should not happen... */
-			break;
-		default:
-			g_assert_not_reached ();
+			default:
+				g_assert_not_reached();
+			}
+			
+			// Pass to next relation
+			relation = relation->next;
+		}
+		
+		// Check if any recursivity bits are still in the status, and in any case clear them
+		if (context->status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
+			if (TRACE_ABC_REMOVAL) {
+				printf ("Recursivity for varible %d (target variable %d) discards computation, status ", variable, target_variable);
+				print_evaluation_context_status (context->status);
+				printf ("\n");
+			}
+			// If yes, we did not have enough information (most likely we were evaluated inside a PHI, but we also
+			// depended on the same PHI, which was still in evaluation...), so clear the status to "NOT_STARTED"
+			// (if we will be evaluated again, the PHI will be already done, so our evaluation will succeed)
+			context->status = MONO_RELATIONS_EVALUATION_NOT_STARTED;
+		} else {
+			if (TRACE_ABC_REMOVAL) {
+				printf ("Ranges for varible %d (target variable %d) computated: ", variable, target_variable);
+				print_evaluation_context_ranges (&(context->ranges));
+				printf ("\n");
+			}
+			// If not (the common case) the evaluation is complete, and the result is in the context
+			context->status = MONO_RELATIONS_EVALUATION_COMPLETED;
 		}
 		break;
 	}
 	case MONO_RELATIONS_EVALUATION_IN_PROGRESS: {
-		MonoVariableRelations *recursive_value_relations = NULL;
-		unsigned char recursive_relation = MONO_ANY_RELATION;
-		MonoRelationsEvaluationContext *current_context = context.father_context;
+		// This means we are in a recursive loop
+		MonoRelationsEvaluationContext *current_context = father_context;
+		MonoRelationsEvaluationContext *last_context = context->father;
+		gboolean evaluation_can_be_recursive = TRUE;
+		gboolean evaluation_is_definition = TRUE;
+		int path_value = 0;
+		
 		if (TRACE_ABC_REMOVAL) {
-			printf ("Current step is MONO_RELATIONS_EVALUATION_IN_PROGRESS\n");
+			printf ("Evaluation of varible %d (target variable %d) already in progress\n", variable, target_variable);
+			print_evaluation_context (context);
+			print_summarized_value_relation (context->current_relation);
+			printf ("\n");
 		}
-		relations->definition_is_recursive = 1;
-		while (current_context != NULL && current_context->variable != variable) {
-			MonoVariableRelations *context_relations = &(evaluation_area->variable_relations [current_context->variable]);
-			MonoSummarizedValue *context_value = &(evaluation_area->variable_definitions [current_context->variable]);
-			if (TRACE_ABC_REMOVAL) {
-				printf ("Backtracing to context %d\n", current_context->variable);
+		
+		// We must check if the loop can be a recursive definition (we scan the whole loop)
+		while (current_context != last_context) {
+			if (current_context == NULL) {
+				printf ("Broken recursive ring in ABC removal\n");
+				g_assert_not_reached ();
 			}
-			if (recursive_value_relations == NULL) {
-				if (context_value->relation_with_value != MONO_EQ_RELATION) {
-					recursive_value_relations = context_relations;
-					recursive_relation = context_value->relation_with_value;
-					if (TRACE_ABC_REMOVAL) {
-						printf ("Accepted recursive definition, relation is ");
-						print_relation (recursive_relation);
-						printf ("\n");
-					}
+			
+			if (current_context->current_relation->relation_is_static_definition) {
+				if (current_context->current_relation->related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
+					path_value += current_context->current_relation->related_value.value.variable.delta;
+				} else if (current_context->current_relation->related_value.type != MONO_PHI_SUMMARIZED_VALUE) {
+					evaluation_can_be_recursive = FALSE;
 				}
 			} else {
-				if (context_value->relation_with_value != MONO_EQ_RELATION) {
-					recursive_relation = MONO_NO_RELATION;
-					if (TRACE_ABC_REMOVAL) {
-						printf ("Rejected recursive definition, bad relation is ");
-						print_relation (context_value->relation_with_value);
-						printf ("\n");
-					}
-				}
+				evaluation_is_definition = FALSE;
+				evaluation_can_be_recursive = FALSE;
 			}
-			current_context = current_context->father_context;
+			
+			current_context = current_context->father;
 		}
-		if (recursive_value_relations != NULL && recursive_relation != MONO_NO_RELATION) {
-			int i;
-			/* This should handle "grows" and "decreases" cases */
-			recursive_value_relations->relation_with_zero &= recursive_relation;
-			for (i = 0; i < evaluation_area->cfg->num_varinfo; i++) {
-				recursive_value_relations->relations_with_variables [i] &= recursive_relation;
+		
+		// If this is a recursive definition, we properly flag the status in all the involved contexts
+		if (evaluation_is_definition) {
+			MonoRelationsEvaluationStatus recursive_status;
+			if (evaluation_can_be_recursive) {
+				if (path_value > 0) {
+					recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING;
+				} else if (path_value < 0) {
+					recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING;
+				} else {
+					recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE;
+				}
+			} else {
+				recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE;
+			}
+			
+			if (TRACE_ABC_REMOVAL) {
+				printf ("Recursivity accepted (");
+				print_evaluation_context_status (recursive_status);
+				printf (")\n");
+			}
+			
+			current_context = father_context;
+			while (current_context != last_context) {
+				current_context->status |= recursive_status;
+				current_context = current_context->father;
+			}
+		} else {
+			if (TRACE_ABC_REMOVAL) {
+				printf ("Recursivity rejected (some relation in the cycle is not a defintion)\n");
 			}
 		}
+		break;
+	}
+	case MONO_RELATIONS_EVALUATION_COMPLETED: {
 		return;
 	}
-	case MONO_RELATIONS_EVALUATION_COMPLETED:
+	default:
 		if (TRACE_ABC_REMOVAL) {
-			printf ("Current step is MONO_RELATIONS_EVALUATION_COMPLETED\n");
+			printf ("Varible %d (target variable %d) already in a recursive ring, skipping\n", variable, target_variable);
+			print_evaluation_context (context);
+			print_summarized_value_relation (context->current_relation);
+			printf ("\n");
 		}
-		return;
-	default:
-		g_assert_not_reached ();
+		break;
 	}
-
-	relations->evaluation_step = MONO_RELATIONS_EVALUATION_COMPLETED;
+	
 }
 
-static int
-propagate_relations (MonoVariableRelationsEvaluationArea *evaluation_area) {
-	int changes = 0;
-	gssize variable;
-	for (variable = 0; variable < evaluation_area->cfg->num_varinfo; variable++) {
-		MonoVariableRelations *relations = &(evaluation_area->variable_relations [variable]);
-		gssize related_variable;
-		for (related_variable = 0; related_variable < evaluation_area->cfg->num_varinfo; related_variable++) {
-			unsigned char relation_with_variable = relations->relations_with_variables [related_variable];
-			if (relation_with_variable != MONO_ANY_RELATION) {
-				MonoVariableRelations *related_relations = &(evaluation_area->variable_relations [related_variable]);
-				gssize variable_related_to_related_variable;
-				unsigned char new_relation_with_zero = PROPAGATED_RELATION (relation_with_variable, related_relations->relation_with_zero);
-				if (RELATION_ADDS_INFORMATION (relations->relation_with_zero, new_relation_with_zero)) {
-					if (TRACE_ABC_REMOVAL) {
-						printf ("RELATION_ADDS_INFORMATION variable %d, related_variable %d, relation_with_zero ",
-							variable, related_variable);
-						print_relation (relations->relation_with_zero);
-						printf (" - ");
-						print_relation (new_relation_with_zero);
-						printf (" => ");
+
+/**
+ * Attempt the removal of bounds checks from a MonoInst.
+ * inst: the MonoInst
+ * area: the current evaluation area (it contains the relation graph and
+ *       memory for all the evaluation contexts is already allocated)
+ */
+static void
+remove_abc_from_inst (MonoInst *inst, MonoVariableRelationsEvaluationArea *area) {
+	if (inst->opcode == CEE_LDELEMA) {
+		MonoInst *array_inst = inst->inst_left;
+		MonoInst *index_inst = inst->inst_right;
+		
+		// The array must be a local variable and the index must be a properly summarized value
+		if ((array_inst->opcode == CEE_LDIND_REF) &&
+				((array_inst->inst_left->opcode == OP_LOCAL)||(array_inst->inst_left->opcode == OP_ARG))) {
+			gssize array_variable = array_inst->inst_left->inst_c0;
+			MonoRelationsEvaluationContext *array_context = &(area->contexts [array_variable]);
+			MonoSummarizedValue index_value;
+			
+			summarize_value (index_inst, &index_value);
+			if (index_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) {
+				// The easiest case: we just evaluate the array length, to see if it has some relation
+				// with the index constant, and act accordingly
+				
+				clean_contexts (area->contexts, area->cfg->num_varinfo);
+				evaluate_relation_with_target_variable (area, array_variable, array_variable, NULL);
+				
+				if ((index_value.value.constant.value >= 0) && (index_value.value.constant.value < array_context->ranges.zero.lower)) {
+					if (REPORT_ABC_REMOVAL) {
+						printf ("ARRAY-ACCESS: removed bounds check on array %d with constant index %d in method %s\n",
+								array_variable, index_value.value.constant.value, mono_method_full_name (area->cfg->method, TRUE));
 					}
-					relations->relation_with_zero &= new_relation_with_zero;
+					inst->flags |= (MONO_INST_NORANGECHECK);
+				}
+			} else if (index_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
+				// The common case: we must evaluate both the index and the array length, and check for relevant
+				// relations both through variable definitions and as constant definitions
+				
+				gssize index_variable = index_value.value.variable.variable;
+				MonoRelationsEvaluationContext *index_context = &(area->contexts [index_variable]);
+				
+				clean_contexts (area->contexts, area->cfg->num_varinfo);
+				
+				evaluate_relation_with_target_variable (area, index_variable, array_variable, NULL);
+				evaluate_relation_with_target_variable (area, array_variable, array_variable, NULL);
+				
+				MONO_SUB_DELTA_SAFELY_FROM_RANGES (index_context->ranges, index_value.value.variable.delta);
+				
+				if (index_context->ranges.zero.lower >= 0) {
 					if (TRACE_ABC_REMOVAL) {
-						print_relation (relations->relation_with_zero);
-						printf ("\n");
+						printf ("ARRAY-ACCESS: Removed lower bound check on array %d with index %d\n", array_variable, index_variable);
 					}
-					changes++;
-				}
-				for (variable_related_to_related_variable = 0; variable_related_to_related_variable < evaluation_area->cfg->num_varinfo; variable_related_to_related_variable++) {
-					unsigned char relation_of_variable = related_relations->relations_with_variables [variable_related_to_related_variable];
-					unsigned char relation_with_other_variable = relations->relations_with_variables [variable_related_to_related_variable];
-					unsigned char new_relation_with_other_variable = PROPAGATED_RELATION (relation_with_variable, relation_of_variable);
-					if (RELATION_ADDS_INFORMATION (relation_with_other_variable, new_relation_with_other_variable)) {
-						if (TRACE_ABC_REMOVAL) {
-							printf ("RELATION_ADDS_INFORMATION variable %d, related_variable %d, variable_related_to_related_variable %d, ",
-								variable, related_variable, variable_related_to_related_variable);
-							print_relation (relation_with_variable);
-							printf (" - ");
-							print_relation (new_relation_with_other_variable);
-							printf (" => ");
-						}
-						relations->relations_with_variables [variable_related_to_related_variable] &= new_relation_with_other_variable;
-						if (TRACE_ABC_REMOVAL) {
-							print_relation (relations->relations_with_variables [variable_related_to_related_variable]);
-							printf ("\n");
+					if ((index_context->ranges.variable.upper < 0)||(index_context->ranges.zero.upper < array_context->ranges.zero.lower)) {
+						if (REPORT_ABC_REMOVAL) {
+							printf ("ARRAY-ACCESS: removed bounds check on array %d with index %d in method %s\n",
+									array_variable, index_variable, mono_method_full_name (area->cfg->method, TRUE));
 						}
-						changes++;
+						inst->flags |= (MONO_INST_NORANGECHECK);
+					}
+				}
+				if (TRACE_ABC_REMOVAL) {
+					if (index_context->ranges.variable.upper < 0) {
+						printf ("ARRAY-ACCESS: Removed upper bound check (through variable) on array %d with index %d\n", array_variable, index_variable);
+					}
+					if (index_context->ranges.zero.upper < array_context->ranges.zero.lower) {
+						printf ("ARRAY-ACCESS: Removed upper bound check (through constant) on array %d with index %d\n", array_variable, index_variable);
 					}
 				}
 			}
+			
 		}
 	}
-	return changes;
 }
 
+/**
+ * Recursively scan a tree of MonoInst looking for array accesses.
+ * inst: the root of the MonoInst tree
+ * area: the current evaluation area (it contains the relation graph and
+ *       memory for all the evaluation contexts is already allocated)
+ */
 static void
-remove_abc_from_inst (MonoInst *inst, MonoVariableRelationsEvaluationArea *evaluation_area) {
-	if (inst->opcode == CEE_LDELEMA) {
-		MonoInst *array_inst = inst->inst_left;
-		MonoInst *index_inst = inst->inst_right;
-		/* Both the array and the index must be local variables */
-		if ((array_inst->opcode == CEE_LDIND_REF) &&
-				((array_inst->inst_left->opcode == OP_LOCAL)||(array_inst->inst_left->opcode == OP_ARG)) &&
-				((index_inst->opcode == CEE_LDIND_I1) ||
-				(index_inst->opcode == CEE_LDIND_U1) ||
-				(index_inst->opcode == CEE_LDIND_I2) ||
-				(index_inst->opcode == CEE_LDIND_U2) ||
-				(index_inst->opcode == CEE_LDIND_I4) ||
-				(index_inst->opcode == CEE_LDIND_U4))&&
-				((index_inst->inst_left->opcode == OP_LOCAL)||(index_inst->inst_left->opcode == OP_ARG))) {
-			gssize array_variable = array_inst->inst_left->inst_c0;
-			gssize index_variable = index_inst->inst_left->inst_c0;
-			MonoVariableRelations *index_relations = &(evaluation_area->variable_relations [index_variable]);
-			if ( (! (index_relations->relation_with_zero & ~MONO_GE_RELATION)) && 
-					(! (index_relations->relations_with_variables [array_variable] & ~MONO_LT_RELATION)) ) {
-				inst->flags |= (MONO_INST_NORANGECHECK);
-			}
-			if (TRACE_ABC_REMOVAL) {
-				if (! (index_relations->relation_with_zero & ~MONO_GE_RELATION)) {
-					printf ("ARRAY-ACCESS: Removed lower bound check on array %d with index %d\n", array_variable, index_variable);
-				} else {
-					printf ("ARRAY-ACCESS: Left lower bound check on array %d with index %d\n", array_variable, index_variable);
-				}
-				if (! (index_relations->relations_with_variables [array_variable] & ~MONO_LT_RELATION)) {
-					printf ("ARRAY-ACCESS: Removed upper bound check on array %d with index %d\n", array_variable, index_variable);
-				} else {
-					printf ("ARRAY-ACCESS: Left upper bound check on array %d with index %d\n", array_variable, index_variable);
-				}
-			}
-			if (REPORT_ABC_REMOVAL) {
-				if (inst->flags & (MONO_INST_NORANGECHECK)) {
-					printf ("ARRAY-ACCESS: removed bounds check on array %d with index %d in method %s\n",
-						array_variable, index_variable, mono_method_full_name (evaluation_area->cfg->method, TRUE));
-				}
-			}
+process_inst (MonoInst *inst, MonoVariableRelationsEvaluationArea *area) {
+	if (inst->opcode == CEE_LDELEMA) { /* Handle OP_LDELEMA2D, too */
+		if (TRACE_ABC_REMOVAL) {
+			printf ("Attempting check removal...\n");
 		}
+		
+		remove_abc_from_inst (inst, area);
 	}
-	
+
 	if (mono_burg_arity [inst->opcode]) {
-		remove_abc_from_inst (inst->inst_left, evaluation_area);
+		process_inst (inst->inst_left, area);
 		if (mono_burg_arity [inst->opcode] > 1) {
-			remove_abc_from_inst (inst->inst_right, evaluation_area);
+			process_inst (inst->inst_right, area);
 		}
 	}
 }
 
+
+
+
+/**
+ * Process a BB removing bounds checks from array accesses.
+ * It does the following (in sequence):
+ * - Get the BB entry condition
+ * - Add its relations to the relation graph in the evaluation area
+ * - Process all the MonoInst trees in the BB
+ * - Recursively process all the children BBs in the dominator tree
+ * - Remove the relations previously added to the relation graph
+ *
+ * bb: the BB that must be processed
+ * area: the current evaluation area (it contains the relation graph and
+ *       memory for all the evaluation contexts is already allocated)
+ */
 static void
-remove_abc_from_block (MonoSummarizedBasicBlock *b, MonoVariableRelationsEvaluationArea *evaluation_area) {
-	int i;
-	int changes;
-	MonoBasicBlock *bb;
-	MonoInst *current_inst = b->block->code;
+process_block (MonoBasicBlock *bb, MonoVariableRelationsEvaluationArea *area) {
+	int inst_index;
+	MonoInst *current_inst;
+	MonoAdditionalVariableRelationsForBB additional_relations;
+	GList *dominated_bb;
 	
 	if (TRACE_ABC_REMOVAL) {
-		printf ("Working on block %d [dfn %d], has_array_access_instructions is %d\n",
-			b->block->block_num, b->block->dfn, b->has_array_access_instructions);
+		printf ("Processing block %d [dfn %d]...\n", bb->block_num, bb->dfn);
 	}
 	
-	if (b->has_array_access_instructions) {
-		for (i = 0; i < evaluation_area->cfg->num_varinfo; i++) {
-			evaluation_area->variable_relations [i].evaluation_step = MONO_RELATIONS_EVALUATION_NOT_STARTED;
-			evaluation_area->variable_relations [i].definition_is_recursive = 0;
-			SET_VARIABLE_RELATIONS (&(evaluation_area->variable_relations [i]), MONO_ANY_RELATION, evaluation_area->cfg->num_varinfo);
-		}
-		
-		bb = b->block;
-		while (bb != NULL) {
-			/* Walk up dominators tree to put conditions in area */
-			int in_index = 0;
-			/* for (in_index = 0; in_index < bb->in_count; in_index++) { */
-			if (bb->in_count == 1) { /* Should write the code to "sum" conditions... */
-				int out_index;
-				MonoBasicBlock *in_bb = bb->in_bb [in_index];
-				MonoSummarizedBasicBlock *in_b = &(evaluation_area->blocks [in_bb->dfn]);
-				for (out_index = 0; out_index < in_b->number_of_branches; out_index++) {
-					if (in_b->branches [out_index].destination_block == bb) {
-						MonoBranchData *branch;
-						int condition_index;
-						if (TRACE_ABC_REMOVAL) {
-							printf ("Applying conditions of branch %d -> %d\n", in_b->block->block_num, bb->block_num);
-						}
-						branch = &(in_b->branches [out_index]);
-						for (condition_index = 0; condition_index < branch->number_of_conditions; condition_index++) {
-							MonoBranchCondition *condition = &(branch->conditions [condition_index]);
-							MonoVariableRelations *relations = &(evaluation_area->variable_relations [condition->variable]);
-							switch (condition->value.value_type) {
-								case MONO_CONSTANT_SUMMARIZED_VALUE: {
-									if (condition->value.relation_with_value == MONO_EQ_RELATION) {
-										relations->relation_with_zero &= RELATION_BETWEEN_VALUES (condition->value.value.constant, 0);
-										relations->relation_with_one &= RELATION_BETWEEN_VALUES (abs (condition->value.value.constant), 1);
-										if (TRACE_ABC_REMOVAL) {
-											printf ("Applied equality condition with constant to variable %d; relatrion with 0: ", condition->variable);
-											print_relation (relations->relation_with_zero);
-											printf ("\n");
-										}
-									} else if (condition->value.value.constant == 0) {
-										relations->relation_with_zero &= condition->value.relation_with_value;
-										if (TRACE_ABC_REMOVAL) {
-											printf ("Applied relation with 0 to variable %d: ", condition->variable);
-											print_relation (relations->relation_with_zero);
-											printf ("\n");
-										}
-									}
-									/* Other cases should be handled */
-									break;
-								}
-								case MONO_VARIABLE_SUMMARIZED_VALUE: {
-									relations->relations_with_variables [condition->value.value.variable] &= condition->value.relation_with_value;
-									if (TRACE_ABC_REMOVAL) {
-										printf ("Applied relation between variables %d and %d: ", condition->variable, condition->value.value.variable);
-										print_relation (relations->relations_with_variables [condition->value.value.variable]);
-										printf ("\n");
-									}
-									break;
-								}
-								default:
-									g_assert_not_reached (); /* PHIs are not OK here */
-							}
-						}
-					}
-				}
-			}
-			bb = bb->idom;
-		}
-		
-		if (TRACE_ABC_REMOVAL) {
-			printf ("Branch conditions applied... ");
-			print_all_variable_relations (evaluation_area);
+	get_relations_from_previous_bb (bb, &additional_relations);
+	if (TRACE_ABC_REMOVAL) {
+		if (additional_relations.relation1.relation.relation != MONO_ANY_RELATION) {
+			printf ("Adding relation 1 on variable %d: ", additional_relations.relation1.variable);
+			print_summarized_value_relation (&(additional_relations.relation1.relation));
+			printf ("\n");
 		}
-		
-		for (i = 0; i < evaluation_area->cfg->num_varinfo; i++) {
-			evaluate_variable_relations (i, evaluation_area, NULL);
+		if (additional_relations.relation2.relation.relation != MONO_ANY_RELATION) {
+			printf ("Adding relation 2 on variable %d: ", additional_relations.relation2.variable);
+			print_summarized_value_relation (&(additional_relations.relation2.relation));
+			printf ("\n");
 		}
-		
+	}
+	apply_change_to_evaluation_area (area, &(additional_relations.relation1));
+	apply_change_to_evaluation_area (area, &(additional_relations.relation2));
+	
+	inst_index = 0;
+	current_inst = bb->code;
+	while (current_inst != NULL) {
 		if (TRACE_ABC_REMOVAL) {
-			printf ("Variable definitions applied... ");
-			print_all_variable_relations (evaluation_area);
+			printf ("Processing instruction %d\n", inst_index);
+			inst_index++;
 		}
 		
-		i = 0;
-		do {
-			changes = propagate_relations (evaluation_area);
-			i++;
-			if (TRACE_ABC_REMOVAL) {
-				printf ("Propagated %d changes\n", changes);
-			}
-		} while ((changes > 0) && (i < evaluation_area->cfg->num_varinfo));
-		
-		if (TRACE_ABC_REMOVAL) {
-			printf ("Relations fully propagated... ");
-			print_all_variable_relations (evaluation_area);
-		}
+		process_inst (current_inst, area);
 		
-		/* Area is ready, look for array access instructions */
-		if (TRACE_ABC_REMOVAL) {
-			printf ("Going after array accesses...\n");
-		}
-		while (current_inst != NULL) {
-			remove_abc_from_inst (current_inst, evaluation_area);
-			current_inst = current_inst->next;
-		}
+		current_inst = current_inst->next;
 	}
+	
+	
+	if (TRACE_ABC_REMOVAL) {
+		printf ("Processing block %d [dfn %d] done.\n", bb->block_num, bb->dfn);
+	}
+	
+	for (dominated_bb = g_list_first (bb->dominated); dominated_bb != NULL; dominated_bb = g_list_next (dominated_bb)) {
+		process_block ((MonoBasicBlock*) (dominated_bb->data), area);
+	}
+	
+	remove_change_from_evaluation_area (&(additional_relations.relation1));
+	remove_change_from_evaluation_area (&(additional_relations.relation2));
 }
 
+
+
+/**
+ * Performs the ABC removal from a cfg in SSA form.
+ * It does the following:
+ * - Prepare the evaluation area
+ * - Allocate memory for the relation graph in the evaluation area
+ *   (of course, only for variable definitions) and summarize there all
+ *   variable definitions
+ * - Allocate memory for the evaluation contexts in the evaluation area
+ * - Recursively process all the BBs in the dominator tree (it is enough
+ *   to invoke the processing on the entry BB)
+ * 
+ * cfg: the method code
+ */
 void
 mono_perform_abc_removal (MonoCompile *cfg)
 {
-	MonoVariableRelationsEvaluationArea evaluation_area;
+	MonoVariableRelationsEvaluationArea area;
 	int i;
-	verbose_level = cfg->verbose_level;
 	
+	verbose_level = cfg->verbose_level;
 	
 	if (TRACE_ABC_REMOVAL) {
 		printf ("Removing array bound checks in %s\n", mono_method_full_name (cfg->method, TRUE));
 	}
 	
-	if (cfg->num_varinfo > 250) {
-		if (TRACE_ABC_REMOVAL) {
-			printf ("Too many variables (%d), giving up...\n", cfg->num_varinfo);
-		}
-		return;
-	}
-	
-	evaluation_area.pool = mono_mempool_new ();
-	evaluation_area.cfg = cfg;
-	evaluation_area.variable_relations = (MonoVariableRelations *)
-		mono_mempool_alloc (evaluation_area.pool, sizeof (MonoVariableRelations) * (cfg->num_varinfo));
-	//printf ("Allocated %d bytes for %d variable relations at pointer %p\n",
-	//	sizeof (MonoVariableRelations) * (cfg->num_varinfo), (cfg->num_varinfo), evaluation_area.variable_relations);
-	for (i = 0; i < cfg->num_varinfo; i++ ) {
-		evaluation_area.variable_relations [i].relations_with_variables = (unsigned char *)
-			mono_mempool_alloc (evaluation_area.pool, (cfg->num_varinfo));
-		//printf ("Allocated %d bytes [%d] at pointer %p\n",
-		//	cfg->num_varinfo, i, evaluation_area.variable_relations [i].relations_with_variables);
-	}
-	evaluation_area.variable_definitions = (MonoSummarizedValue *)
-		mono_mempool_alloc (evaluation_area.pool, sizeof (MonoSummarizedValue) * (cfg->num_varinfo));
-	//printf ("Allocated %d bytes for %d variable definitions at pointer %p\n",
-	//	sizeof (MonoSummarizedValue) * (cfg->num_varinfo), (cfg->num_varinfo), evaluation_area.variable_definitions);
-	if (TRACE_ABC_REMOVAL) {
-		printf ("Method contains %d variables\n", i);
-	}
+	area.cfg = cfg;
+	area.relations = (MonoSummarizedValueRelation *)
+		alloca (sizeof (MonoSummarizedValueRelation) * (cfg->num_varinfo) * 2);
+	area.contexts = (MonoRelationsEvaluationContext *)
+		alloca (sizeof (MonoRelationsEvaluationContext) * (cfg->num_varinfo));
 	for (i = 0; i < cfg->num_varinfo; i++) {
+		area.relations [i].relation = MONO_EQ_RELATION;
+		area.relations [i].relation_is_static_definition = TRUE;
+		area.relations [i].next = NULL;
 		if (cfg->vars [i]->def != NULL) {
-			MonoInst *value = get_variable_value_from_ssa_store (cfg->vars [i]->def, i);
+			MonoInst *value = get_variable_value_from_store_instruction (cfg->vars [i]->def, i);
 			if (value != NULL) {
-				summarize_value (value, evaluation_area.variable_definitions + i);
+				summarize_value (value, &(area.relations [i].related_value));
 				if (TRACE_ABC_REMOVAL) {
-					printf ("Summarized variable %d\n", i);
-					print_summarized_value (evaluation_area.variable_definitions + i);
+					printf ("Summarized variable %d: ", i);
+					print_summarized_value (&(area.relations [i].related_value));
+					printf ("\n");
 				}
 			} else {
-				MAKE_VALUE_ANY (evaluation_area.variable_definitions + i);
+				MAKE_VALUE_ANY (area.relations [i].related_value);
 				if (TRACE_ABC_REMOVAL) {
 					printf ("Definition of variable %d is not a proper store\n", i);
 				}
 			}
 		} else {
-			MAKE_VALUE_ANY (evaluation_area.variable_definitions + i);
+			MAKE_VALUE_ANY (area.relations [i].related_value);
 			if (TRACE_ABC_REMOVAL) {
 				printf ("Variable %d has no definition, probably it is an argument\n", i);
-				print_summarized_value (evaluation_area.variable_definitions + i);
 			}
 		}
 	}
-	
-	evaluation_area.blocks = (MonoSummarizedBasicBlock *)
-		mono_mempool_alloc (evaluation_area.pool, sizeof (MonoSummarizedBasicBlock) * (cfg->num_bblocks));
-	//printf ("Allocated %d bytes for %d blocks at pointer %p\n",
-	//	sizeof (MonoSummarizedBasicBlock) * (cfg->num_bblocks), (cfg->num_bblocks), evaluation_area.blocks);
-	
-	for (i = 0; i < cfg->num_bblocks; i++) {
-		analyze_block (cfg->bblocks [i], &evaluation_area);
-	}
-	
-	for (i = 0; i < cfg->num_bblocks; i++) {
-		remove_abc_from_block (&(evaluation_area.blocks [i]), &evaluation_area);
-	}
-	
-	mono_mempool_destroy (evaluation_area.pool);
-}
-
-#else
-static void remove_abc (MonoInst *inst) {
-	if (inst->opcode == CEE_LDELEMA) {
-		if (TRACE_ABC_REMOVAL||REPORT_ABC_REMOVAL) {
-			printf ("Performing removal...\n");
+	for (i = 0; i < cfg->num_varinfo; i++) {
+		if (area.relations [i].related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
+			int related_index = cfg->num_varinfo + i;
+			int related_variable = area.relations [i].related_value.value.variable.variable;
+			
+			area.relations [related_index].relation = MONO_EQ_RELATION;
+			area.relations [related_index].relation_is_static_definition = TRUE;
+			area.relations [related_index].related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
+			area.relations [related_index].related_value.value.variable.variable = i;
+			area.relations [related_index].related_value.value.variable.delta = - area.relations [i].related_value.value.variable.delta;
+			
+			area.relations [related_index].next = area.relations [related_variable].next;
+			area.relations [related_variable].next = &(area.relations [related_index]);
+			
+			if (TRACE_ABC_REMOVAL) {
+				printf ("Added symmetric summarized value for variable variable %d (to %d): ", i, related_variable);
+				print_summarized_value (&(area.relations [related_index].related_value));
+				printf ("\n");
+			}
 		}
-		inst->flags |= (MONO_INST_NORANGECHECK);
 	}
 	
-	if (mono_burg_arity [inst->opcode]) {
-		remove_abc (inst->inst_left);
-		if (mono_burg_arity [inst->opcode] > 1) {
-			remove_abc (inst->inst_right);
-		}
-	}
+	process_block (cfg->bblocks [0], &area);
 }
 
-void
-mono_perform_abc_removal (MonoCompile *cfg) {
-	verbose_level = cfg->verbose_level;
-	
-	int i;
-	#if (TRACE_ABC_REMOVAL)
-	printf ("Removing array bound checks in %s\n", mono_method_full_name (cfg->method, TRUE));
-	#endif
-	
-	for (i = 0; i < cfg->num_bblocks; i++) {
-		#if (TRACE_ABC_REMOVAL)
-		printf ("  Working on block %d [dfn %d]\n", cfg->bblocks [i]->block_num, i);
-		#endif
-		
-		MonoBasicBlock *bb = cfg->bblocks [i];
-		MonoInst *inst = bb->code;
-		while (inst != NULL) {
-			remove_abc (inst);
-			inst = inst->next;
-		}
-	}
-}
-#endif

+ 273 - 52
mono/mini/abcremoval.h

@@ -10,9 +10,75 @@
 #ifndef __MONO_ABCREMOVAL_H__
 #define __MONO_ABCREMOVAL_H__
 
+#include <limits.h>
+
 #include "mini.h"
 
 
+/**
+ * All handled value types (expressions) in variable definitions and branch
+ * contitions:
+ * ANY: not handled
+ * CONSTANT: an integer constant
+ * VARIABLE: a reference to a variable, with an optional delta (can be zero)
+ * PHI: a PHI definition of the SSA representation
+ */
+typedef enum {
+	MONO_ANY_SUMMARIZED_VALUE,
+	MONO_CONSTANT_SUMMARIZED_VALUE,
+	MONO_VARIABLE_SUMMARIZED_VALUE,
+	MONO_PHI_SUMMARIZED_VALUE
+} MonoSummarizedValueType;
+
+/**
+ * A MONO_CONSTANT_SUMMARIZED_VALUE value.
+ * value: the value
+ */
+typedef struct MonoSummarizedConstantValue {
+	int value;
+} MonoSummarizedConstantValue;
+
+/**
+ * A MONO_VARIABLE_SUMMARIZED_VALUE value
+ * variable: the variable index in the cfg
+ * delta: the delta (can be zero)
+ */
+typedef struct MonoSummarizedVariableValue {
+	gssize variable;
+	int delta;
+} MonoSummarizedVariableValue;
+
+/**
+ * A MONO_PHI_SUMMARIZED_VALUE value.
+ * number_of_alternatives: the number of alternatives in the PHI definition
+ * phi_alternatives: an array of integers with the indexes of the variables
+ *                   which are the alternatives in this PHI definition
+ */
+typedef struct MonoSummarizedPhiValue {
+	int number_of_alternatives;
+	int *phi_alternatives;
+} MonoSummarizedPhiValue;
+
+/**
+ * A summarized value.
+ * In practice it is a "tagged union".
+ */
+typedef struct MonoSummarizedValue {
+	MonoSummarizedValueType type;
+	union {
+		MonoSummarizedConstantValue constant;
+		MonoSummarizedVariableValue variable;
+		MonoSummarizedPhiValue phi;
+	} value;
+} MonoSummarizedValue;
+
+/**
+ * A "relation" between two values.
+ * The enumeration is used as a bit field, with three significant bits.
+ * The degenerated cases are meaningful:
+ * MONO_ANY_RELATION: we know nothing of this relation
+ * MONO_NO_RELATION: no relation is possible (this code is unreachable)
+ */
 typedef enum {
 	MONO_EQ_RELATION = 1,
 	MONO_LT_RELATION = 2,
@@ -24,71 +90,226 @@ typedef enum {
 	MONO_NO_RELATION = 0
 } MonoValueRelation;
 
+/**
+ * A relation between variables (or a variable and a constant).
+ * The first variable (the one "on the left of the expression") is implicit.
+ * relation: the relation between the variable and the value
+ * related_value: the related value
+ * relation_is_static_definition: TRUE if the relation comes from a veriable
+ *                                definition, FALSE if it comes from a branch
+ *                                condition
+ * next: pointer to the next relation of this variable in the evaluation area
+ *       (relations are always kept in the evaluation area, one list for each
+ *       variable)
+ */
+typedef struct MonoSummarizedValueRelation {
+	MonoValueRelation relation;
+	MonoSummarizedValue related_value;
+	gboolean relation_is_static_definition;
+	struct MonoSummarizedValueRelation *next;
+} MonoSummarizedValueRelation;
 
+/**
+ * The evaluation status for one variable.
+ * The enumeration is used as a bit field, because the status has two
+ * distinct sections.
+ * The first is the "main" one (bits 0, 1 and 2), which is actually a proper
+ * enumeration (the bits are mutually exclusive, and their meaning is obvious).
+ * The other section (the bits in the MONO_RELATIONS_EVALUATION_IS_RECURSIVE
+ * set) is used to mark an evaluation as recursive (while backtracking through
+ * the evaluation contexts), to state if the graph loop gives a value that is
+ * ascending, descending or indefinite.
+ * The bits are handled separately because the same evaluation context could
+ * belong to more than one loop, so that each loop would set its bits.
+ * After the backtracking, the bits are examined and a decision is taken.
+ * 
+ */
 typedef enum {
-	MONO_CONSTANT_SUMMARIZED_VALUE = 0,
-	MONO_VARIABLE_SUMMARIZED_VALUE,
-	MONO_PHI_SUMMARIZED_VALUE
-} MonoSummarizedValueType;
+	MONO_RELATIONS_EVALUATION_NOT_STARTED = 0,
+	MONO_RELATIONS_EVALUATION_IN_PROGRESS = 1,
+	MONO_RELATIONS_EVALUATION_COMPLETED = 2,
+	MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING = 4,
+	MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING = 8,
+	MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE = 16,
+	MONO_RELATIONS_EVALUATION_IS_RECURSIVE = (MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING|MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING|MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE)
+} MonoRelationsEvaluationStatus;
 
+/**
+ * A range of values (ranges include their limits).
+ * A range from MIN_INT to MAX_INT is "indefinite" (any value).
+ * A range where upper < lower means unreachable code (some of the relations
+ * that generated the range is incompatible, like x = 0 and x > 0).
+ * lower: the lower limit
+ * upper: the upper limit
+ */
+typedef struct MonoRelationsEvaluationRange {
+	int lower;
+	int upper;
+} MonoRelationsEvaluationRange;
 
-typedef struct MonoSummarizedValue {
-	unsigned char relation_with_zero; /* MonoValueRelation */
-	unsigned char relation_with_one; /* MonoValueRelation */
-	unsigned char relation_with_value; /* MonoValueRelation */
-	unsigned char value_type; /* MonoSummarizedValueType */
-	union {
-		int constant;
-		gssize variable;
-		int *phi_variables;
-	} value;
-} MonoSummarizedValue;
+/**
+ * The two ranges that contain the result of a variable evaluation.
+ * zero: the range with respect to zero
+ * variable: the range with respect to the target variable in this evaluation
+ */
+typedef struct MonoRelationsEvaluationRanges {
+	MonoRelationsEvaluationRange zero;
+	MonoRelationsEvaluationRange variable;
+} MonoRelationsEvaluationRanges;
 
+/**
+ * The context of a variable evaluation.
+ * status: the evaluation status
+ * current_relation: the relation that is currently evaluated.
+ * ranges: the result of the evaluation.
+ * father: the context of the evaluation that invoked this one (used to
+ *         perform the backtracking when loops are detected.
+ */
+typedef struct MonoRelationsEvaluationContext {
+	MonoRelationsEvaluationStatus status;
+	MonoSummarizedValueRelation *current_relation;
+	MonoRelationsEvaluationRanges ranges;
+	struct MonoRelationsEvaluationContext *father;
+} MonoRelationsEvaluationContext;
 
-typedef struct MonoBranchCondition {
-	gssize variable;
-	MonoSummarizedValue value;
-} MonoBranchCondition;
-
-typedef struct MonoBranchData {
-	MonoBasicBlock *destination_block;
-	int number_of_conditions;
-	MonoBranchCondition *conditions;
-} MonoBranchData;
-
-typedef struct MonoSummarizedBasicBlock {
-	MonoBasicBlock *block;
-	unsigned char has_array_access_instructions;
-	int number_of_branches;
-	MonoBranchData* branches;
-} MonoSummarizedBasicBlock;
+/*
+ * Basic macros to initialize and check ranges.
+ */
+#define MONO_MAKE_RELATIONS_EVALUATION_RANGE_WEAK(r) do{\
+		(r).lower = INT_MIN;\
+		(r).upper = INT_MAX;\
+	} while (0)
+#define MONO_MAKE_RELATIONS_EVALUATION_RANGES_WEAK(rs) do{\
+		MONO_MAKE_RELATIONS_EVALUATION_RANGE_WEAK ((rs).zero); \
+		MONO_MAKE_RELATIONS_EVALUATION_RANGE_WEAK ((rs).variable); \
+	} while (0)
+#define MONO_MAKE_RELATIONS_EVALUATION_RANGE_IMPOSSIBLE(r) do{\
+		(r).lower = INT_MAX;\
+		(r).upper = INT_MIN;\
+	} while (0)
+#define MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE(rs) do{\
+		MONO_MAKE_RELATIONS_EVALUATION_RANGE_IMPOSSIBLE ((rs).zero); \
+		MONO_MAKE_RELATIONS_EVALUATION_RANGE_IMPOSSIBLE ((rs).variable); \
+	} while (0)
+#define MONO_RELATIONS_EVALUATION_RANGE_IS_IMPOSSIBLE(r) (((r).lower==INT_MAX)&&((r).upper==INT_MIN))
+#define MONO_RELATIONS_EVALUATION_RANGES_IS_IMPOSSIBLE(rs) \
+	(MONO_RELATIONS_EVALUATION_RANGE_IS_IMPOSSIBLE((rs).zero) && \
+	MONO_RELATIONS_EVALUATION_RANGE_IS_IMPOSSIBLE((rs).variable))
 
-typedef enum {
-	MONO_RELATIONS_EVALUATION_NOT_STARTED,
-	MONO_RELATIONS_EVALUATION_IN_PROGRESS,
-	MONO_RELATIONS_EVALUATION_COMPLETED
-} MonoRelationsEvaluationStep;
-
-typedef struct MonoVariableRelations {
-	unsigned char relation_with_zero; /* MonoValueRelation */
-	unsigned char relation_with_one; /* MonoValueRelation */
-	unsigned char evaluation_step; /* MonoRelationsEvaluationStep */
-	unsigned char definition_is_recursive;
-	unsigned char *relations_with_variables; /* many MonoValueRelation */
-} MonoVariableRelations;
+/*
+ * The following macros are needed because ranges include theit limits, but
+ * some relations explicitly exclude them (GT and LT).
+ */
+#define MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL(ur) ((((ur)==INT_MIN)||((ur)==INT_MAX))?(ur):((ur)-1))
+#define MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL(lr) ((((lr)==INT_MIN)||((lr)==INT_MAX))?(lr):((lr)+1))
+#define MONO_APPLY_INEQUALITY_TO_EVALUATION_RANGE(r) do{\
+		(r).lower = MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL ((r).lower);\
+		(r).upper = MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL ((r).upper);\
+	} while (0)
+#define MONO_APPLY_INEQUALITY_TO_EVALUATION_RANGES(rs) do{\
+		MONO_APPLY_INEQUALITY_TO_EVALUATION_RANGE ((rs).zero); \
+		MONO_APPLY_INEQUALITY_TO_EVALUATION_RANGE ((rs).variable); \
+	} while (0)
 
+/*
+ * The following macros perform union and intersection operations on ranges.
+ */
+#define MONO_LOWER_EVALUATION_RANGE_UNION(lr,other_lr) ((lr)=MIN(lr,other_lr))
+#define MONO_UPPER_EVALUATION_RANGE_UNION(ur,other_ur) ((ur)=MAX(ur,other_ur))
+#define MONO_LOWER_EVALUATION_RANGE_INTERSECTION(lr,other_lr) ((lr)=MAX(lr,other_lr))
+#define MONO_UPPER_EVALUATION_RANGE_INTERSECTION(ur,other_ur) ((ur)=MIN(ur,other_ur))
+#define MONO_RELATIONS_EVALUATION_RANGE_UNION(r,other_r) do{\
+		MONO_LOWER_EVALUATION_RANGE_UNION((r).lower,(other_r).lower);\
+		MONO_UPPER_EVALUATION_RANGE_UNION((r).upper,(other_r).upper);\
+	} while (0)
+#define MONO_RELATIONS_EVALUATION_RANGE_INTERSECTION(r,other_r) do{\
+		MONO_LOWER_EVALUATION_RANGE_INTERSECTION((r).lower,(other_r).lower);\
+		MONO_UPPER_EVALUATION_RANGE_INTERSECTION((r).upper,(other_r).upper);\
+	} while (0)
+#define MONO_RELATIONS_EVALUATION_RANGES_UNION(rs,other_rs) do{\
+		MONO_RELATIONS_EVALUATION_RANGE_UNION ((rs).zero,(other_rs).zero); \
+		MONO_RELATIONS_EVALUATION_RANGE_UNION ((rs).variable,(other_rs).variable); \
+	} while (0)
+#define MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION(rs,other_rs) do{\
+		MONO_RELATIONS_EVALUATION_RANGE_INTERSECTION ((rs).zero,(other_rs).zero); \
+		MONO_RELATIONS_EVALUATION_RANGE_INTERSECTION ((rs).variable,(other_rs).variable); \
+	} while (0)
+
+/*
+ * The following macros add or subtract "safely" (without over/under-flow) a
+ * delta (constant) value to a range.
+ */
+#define MONO_ADD_DELTA_SAFELY(v,d) do{\
+		if (((d) > 0) && ((v) != INT_MIN)) {\
+			(v) = (((v)+(d))>(v))?((v)+(d)):INT_MAX;\
+		} else if (((d) < 0) && ((v) != INT_MAX)) {\
+			(v) = (((v)+(d))<(v))?((v)+(d)):INT_MIN;\
+		}\
+	} while (0)
+#define MONO_SUB_DELTA_SAFELY(v,d) do{\
+		if (((d) < 0) && ((v) != INT_MIN)) {\
+			(v) = (((v)-(d))>(v))?((v)-(d)):INT_MAX;\
+		} else if (((d) > 0) && ((v) != INT_MAX)) {\
+			(v) = (((v)-(d))<(v))?((v)-(d)):INT_MIN;\
+		}\
+	} while (0)
+#define MONO_ADD_DELTA_SAFELY_TO_RANGE(r,d) do{\
+		MONO_ADD_DELTA_SAFELY((r).lower,(d));\
+		MONO_ADD_DELTA_SAFELY((r).upper,(d));\
+	} while (0)
+#define MONO_SUB_DELTA_SAFELY_FROM_RANGE(r,d) do{\
+		MONO_SUB_DELTA_SAFELY((r).lower,(d));\
+		MONO_SUB_DELTA_SAFELY((r).upper,(d));\
+	} while (0)
+#define MONO_ADD_DELTA_SAFELY_TO_RANGES(rs,d) do{\
+		MONO_ADD_DELTA_SAFELY_TO_RANGE((rs).zero,(d));\
+		MONO_ADD_DELTA_SAFELY_TO_RANGE((rs).variable,(d));\
+	} while (0)
+#define MONO_SUB_DELTA_SAFELY_FROM_RANGES(rs,d) do{\
+		MONO_SUB_DELTA_SAFELY_FROM_RANGE((rs).zero,(d));\
+		MONO_SUB_DELTA_SAFELY_FROM_RANGE((rs).variable,(d));\
+	} while (0)
+
+
+/**
+ * The main evaluation area.
+ * cfg: the cfg of the method that is being examined.
+ * relations: and array of relations, one for each method variable (each
+ *            relation is the head of a list); this is the evaluation graph
+ * contexts: an array of evaluation contexts (one for each method variable)
+ */
 typedef struct MonoVariableRelationsEvaluationArea {
 	MonoCompile *cfg;
-	MonoMemPool *pool;
-	MonoVariableRelations *variable_relations;
-	MonoSummarizedValue *variable_definitions;
-	MonoSummarizedBasicBlock *blocks;
+	MonoSummarizedValueRelation *relations;
+	MonoRelationsEvaluationContext *contexts;
 } MonoVariableRelationsEvaluationArea;
 
-typedef struct MonoRelationsEvaluationContext {
-	struct MonoRelationsEvaluationContext *father_context;
+/**
+ * Convenience structure to define an "additional" relation for the main
+ * evaluation graph.
+ * variable: the variable to which the relation is applied
+ * relation: the relation
+ * insertion_point: the point in the graph where the relation is inserted
+ *                  (useful for removing it from the list when backtracking
+ *                  in the traversal of the dominator tree)
+ */
+typedef struct MonoAdditionalVariableRelation {
 	gssize variable;
-} MonoRelationsEvaluationContext;
+	MonoSummarizedValueRelation relation;
+	MonoSummarizedValueRelation *insertion_point;
+} MonoAdditionalVariableRelation;
+
+/**
+ * Convenience structure that stores two additional relations.
+ * In the current code, each BB can add at most two relations to the main
+ * evaluation graph, so one of these structures is enough to hold all the
+ * modifications to the graph made examining one BB.
+ */
+typedef struct MonoAdditionalVariableRelationsForBB {
+	MonoAdditionalVariableRelation relation1;
+	MonoAdditionalVariableRelation relation2;
+} MonoAdditionalVariableRelationsForBB;
+
 
 #endif /* __MONO_ABCREMOVAL_H__ */
 

+ 0 - 126
mono/mini/build_relations_propagation_table.pl

@@ -1,126 +0,0 @@
-#!/usr/bin/perl
-
-# Generate helper table for array bounds check removal
-#
-# Author:
-#   Massimiliano Mantione ([email protected])
-#
-# (C) 2004 Ximian, Inc.  http://www.ximian.com
-
-@relations = (
-  'MONO_NO_RELATION',  # 000
-  'MONO_EQ_RELATION',  # 001
-  'MONO_LT_RELATION',  # 010
-  'MONO_LE_RELATION',  # 011 (MONO_LT_RELATION|MONO_EQ_RELATION)
-  'MONO_GT_RELATION',  # 100
-  'MONO_GE_RELATION',  # 101 (MONO_GT_RELATION|MONO_EQ_RELATION)
-  'MONO_NE_RELATION',  # 110 (MONO_LT_RELATION|MONO_GT_RELATION)
-  'MONO_ANY_RELATION', # 111 (MONO_EQ_RELATION|MONO_LT_RELATION|MONO_GT_RELATION)
-);
-
-sub build_propagated_relation
-{
-  my ( $main_relation, $related_relation ) = @_;
-  my $result = 'MONO_UNKNOWN_RELATION';
-  
-  if ( ($main_relation eq 'MONO_EQ_RELATION') && ($related_relation ne 'MONO_NO_RELATION') )
-  {
-    $result = $related_relation;
-  }
-  elsif ( $main_relation eq 'MONO_LT_RELATION' )
-  {
-    if ( $related_relation eq 'MONO_EQ_RELATION' )
-    {
-      $result = 'MONO_LT_RELATION';
-    }
-    elsif ( $related_relation eq 'MONO_LT_RELATION' )
-    {
-      $result = 'MONO_LT_RELATION';
-    }
-    elsif ( $related_relation eq 'MONO_LE_RELATION' )
-    {
-      $result = 'MONO_LT_RELATION';
-    }
-    else
-    {
-      $result = 'MONO_ANY_RELATION';
-    }
-  }
-  elsif ( $main_relation eq 'MONO_LE_RELATION' )
-  {
-    if ( $related_relation eq 'MONO_EQ_RELATION' )
-    {
-      $result = 'MONO_LE_RELATION';
-    }
-    elsif ( $related_relation eq 'MONO_LT_RELATION' )
-    {
-      $result = 'MONO_LT_RELATION';
-    }
-    elsif ( $related_relation eq 'MONO_LE_RELATION' )
-    {
-      $result = 'MONO_LE_RELATION';
-    }
-    else
-    {
-      $result = 'MONO_ANY_RELATION';
-    }
-  }
-  
-  elsif ( $main_relation eq 'MONO_GT_RELATION' )
-  {
-    if ( $related_relation eq 'MONO_EQ_RELATION' )
-    {
-      $result = 'MONO_GT_RELATION';
-    }
-    elsif ( $related_relation eq 'MONO_GT_RELATION' )
-    {
-      $result = 'MONO_GT_RELATION';
-    }
-    elsif ( $related_relation eq 'MONO_GE_RELATION' )
-    {
-      $result = 'MONO_GT_RELATION';
-    }
-    else
-    {
-      $result = 'MONO_ANY_RELATION';
-    }
-  }
-  elsif ( $main_relation eq 'MONO_GE_RELATION' )
-  {
-    if ( $related_relation eq 'MONO_EQ_RELATION' )
-    {
-      $result = 'MONO_GE_RELATION';
-    }
-    elsif ( $related_relation eq 'MONO_GT_RELATION' )
-    {
-      $result = 'MONO_GT_RELATION';
-    }
-    elsif ( $related_relation eq 'MONO_GE_RELATION' )
-    {
-      $result = 'MONO_GE_RELATION';
-    }
-    else
-    {
-      $result = 'MONO_ANY_RELATION';
-    }
-  }
-  else
-  {
-    $result = 'MONO_ANY_RELATION';
-  }
-  
-  $result;
-}
-
-open FILE, ">propagated_relations_table.def";
-
-for ( my $mr = 0; $mr < 8; $mr++ )
-{
-  for ( my $pr = 0; $pr < 8; $pr++ )
-  {
-    my $propagated_relation = &build_propagated_relation( $relations[$mr], $relations[$pr] );
-    print FILE "  $propagated_relation, /* $relations[$mr] - $relations[$pr] */\n";
-  }
-}
-
-close FILE;

+ 0 - 64
mono/mini/propagated_relations_table.def

@@ -1,64 +0,0 @@
-  MONO_ANY_RELATION, /* MONO_NO_RELATION - MONO_NO_RELATION */
-  MONO_ANY_RELATION, /* MONO_NO_RELATION - MONO_EQ_RELATION */
-  MONO_ANY_RELATION, /* MONO_NO_RELATION - MONO_LT_RELATION */
-  MONO_ANY_RELATION, /* MONO_NO_RELATION - MONO_LE_RELATION */
-  MONO_ANY_RELATION, /* MONO_NO_RELATION - MONO_GT_RELATION */
-  MONO_ANY_RELATION, /* MONO_NO_RELATION - MONO_GE_RELATION */
-  MONO_ANY_RELATION, /* MONO_NO_RELATION - MONO_NE_RELATION */
-  MONO_ANY_RELATION, /* MONO_NO_RELATION - MONO_ANY_RELATION */
-  MONO_ANY_RELATION, /* MONO_EQ_RELATION - MONO_NO_RELATION */
-  MONO_EQ_RELATION, /* MONO_EQ_RELATION - MONO_EQ_RELATION */
-  MONO_LT_RELATION, /* MONO_EQ_RELATION - MONO_LT_RELATION */
-  MONO_LE_RELATION, /* MONO_EQ_RELATION - MONO_LE_RELATION */
-  MONO_GT_RELATION, /* MONO_EQ_RELATION - MONO_GT_RELATION */
-  MONO_GE_RELATION, /* MONO_EQ_RELATION - MONO_GE_RELATION */
-  MONO_NE_RELATION, /* MONO_EQ_RELATION - MONO_NE_RELATION */
-  MONO_ANY_RELATION, /* MONO_EQ_RELATION - MONO_ANY_RELATION */
-  MONO_ANY_RELATION, /* MONO_LT_RELATION - MONO_NO_RELATION */
-  MONO_LT_RELATION, /* MONO_LT_RELATION - MONO_EQ_RELATION */
-  MONO_LT_RELATION, /* MONO_LT_RELATION - MONO_LT_RELATION */
-  MONO_LT_RELATION, /* MONO_LT_RELATION - MONO_LE_RELATION */
-  MONO_ANY_RELATION, /* MONO_LT_RELATION - MONO_GT_RELATION */
-  MONO_ANY_RELATION, /* MONO_LT_RELATION - MONO_GE_RELATION */
-  MONO_ANY_RELATION, /* MONO_LT_RELATION - MONO_NE_RELATION */
-  MONO_ANY_RELATION, /* MONO_LT_RELATION - MONO_ANY_RELATION */
-  MONO_ANY_RELATION, /* MONO_LE_RELATION - MONO_NO_RELATION */
-  MONO_LE_RELATION, /* MONO_LE_RELATION - MONO_EQ_RELATION */
-  MONO_LT_RELATION, /* MONO_LE_RELATION - MONO_LT_RELATION */
-  MONO_LE_RELATION, /* MONO_LE_RELATION - MONO_LE_RELATION */
-  MONO_ANY_RELATION, /* MONO_LE_RELATION - MONO_GT_RELATION */
-  MONO_ANY_RELATION, /* MONO_LE_RELATION - MONO_GE_RELATION */
-  MONO_ANY_RELATION, /* MONO_LE_RELATION - MONO_NE_RELATION */
-  MONO_ANY_RELATION, /* MONO_LE_RELATION - MONO_ANY_RELATION */
-  MONO_ANY_RELATION, /* MONO_GT_RELATION - MONO_NO_RELATION */
-  MONO_GT_RELATION, /* MONO_GT_RELATION - MONO_EQ_RELATION */
-  MONO_ANY_RELATION, /* MONO_GT_RELATION - MONO_LT_RELATION */
-  MONO_ANY_RELATION, /* MONO_GT_RELATION - MONO_LE_RELATION */
-  MONO_GT_RELATION, /* MONO_GT_RELATION - MONO_GT_RELATION */
-  MONO_GT_RELATION, /* MONO_GT_RELATION - MONO_GE_RELATION */
-  MONO_ANY_RELATION, /* MONO_GT_RELATION - MONO_NE_RELATION */
-  MONO_ANY_RELATION, /* MONO_GT_RELATION - MONO_ANY_RELATION */
-  MONO_ANY_RELATION, /* MONO_GE_RELATION - MONO_NO_RELATION */
-  MONO_GE_RELATION, /* MONO_GE_RELATION - MONO_EQ_RELATION */
-  MONO_ANY_RELATION, /* MONO_GE_RELATION - MONO_LT_RELATION */
-  MONO_ANY_RELATION, /* MONO_GE_RELATION - MONO_LE_RELATION */
-  MONO_GT_RELATION, /* MONO_GE_RELATION - MONO_GT_RELATION */
-  MONO_GE_RELATION, /* MONO_GE_RELATION - MONO_GE_RELATION */
-  MONO_ANY_RELATION, /* MONO_GE_RELATION - MONO_NE_RELATION */
-  MONO_ANY_RELATION, /* MONO_GE_RELATION - MONO_ANY_RELATION */
-  MONO_ANY_RELATION, /* MONO_NE_RELATION - MONO_NO_RELATION */
-  MONO_ANY_RELATION, /* MONO_NE_RELATION - MONO_EQ_RELATION */
-  MONO_ANY_RELATION, /* MONO_NE_RELATION - MONO_LT_RELATION */
-  MONO_ANY_RELATION, /* MONO_NE_RELATION - MONO_LE_RELATION */
-  MONO_ANY_RELATION, /* MONO_NE_RELATION - MONO_GT_RELATION */
-  MONO_ANY_RELATION, /* MONO_NE_RELATION - MONO_GE_RELATION */
-  MONO_ANY_RELATION, /* MONO_NE_RELATION - MONO_NE_RELATION */
-  MONO_ANY_RELATION, /* MONO_NE_RELATION - MONO_ANY_RELATION */
-  MONO_ANY_RELATION, /* MONO_ANY_RELATION - MONO_NO_RELATION */
-  MONO_ANY_RELATION, /* MONO_ANY_RELATION - MONO_EQ_RELATION */
-  MONO_ANY_RELATION, /* MONO_ANY_RELATION - MONO_LT_RELATION */
-  MONO_ANY_RELATION, /* MONO_ANY_RELATION - MONO_LE_RELATION */
-  MONO_ANY_RELATION, /* MONO_ANY_RELATION - MONO_GT_RELATION */
-  MONO_ANY_RELATION, /* MONO_ANY_RELATION - MONO_GE_RELATION */
-  MONO_ANY_RELATION, /* MONO_ANY_RELATION - MONO_NE_RELATION */
-  MONO_ANY_RELATION, /* MONO_ANY_RELATION - MONO_ANY_RELATION */