Added array bounds check (ABC) removal optimization.
authorMassimiliano Mantione <massi@mono-cvs.ximian.com>
Fri, 14 May 2004 10:30:10 +0000 (10:30 -0000)
committerMassimiliano Mantione <massi@mono-cvs.ximian.com>
Fri, 14 May 2004 10:30:10 +0000 (10:30 -0000)
svn path=/trunk/mono/; revision=27365

mono/mini/Makefile.am
mono/mini/abcremoval.c [new file with mode: 0644]
mono/mini/abcremoval.h [new file with mode: 0644]
mono/mini/build_relations_propagation_table.pl [new file with mode: 0755]
mono/mini/driver.c
mono/mini/inssel.brg
mono/mini/mini.c
mono/mini/mini.h
mono/mini/propagated_relations_table.def [new file with mode: 0644]

index 2f84442558d1528fc866a05ef7901265be9a679d..216acf914bc1ae0106f2cf3eeb7e589343c754c3 100644 (file)
@@ -107,6 +107,7 @@ common_sources = \
        helpers.c       \
        liveness.c      \
        ssa.c           \
+       abcremoval.c    \
        driver.c        \
        debug-mini.c    \
        linear-scan.c   \
diff --git a/mono/mini/abcremoval.c b/mono/mini/abcremoval.c
new file mode 100644 (file)
index 0000000..f560ab3
--- /dev/null
@@ -0,0 +1,1042 @@
+
+#include <string.h>
+#include <stdio.h>
+
+#include <mono/metadata/debug-helpers.h>
+#include <mono/metadata/mempool.h>
+#include <mono/metadata/opcodes.h>
+
+#include "mini.h"
+#include "inssel.h"
+
+#include "abcremoval.h"
+
+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
+
+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;\
+       } 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 print_relation(int relation){
+       int print_or = 0;
+       printf("(");
+       if (relation & MONO_LT_RELATION){
+               printf("LT");
+               print_or = 1;
+       }
+       if (relation & MONO_EQ_RELATION){
+               if (print_or){
+                       printf("|");
+               }
+               printf("EQ");
+               print_or = 1;
+       }
+       if (relation & MONO_GT_RELATION){
+               if (print_or){
+                       printf("|");
+               }
+               printf("GT");
+               print_or = 1;
+       }
+       printf(")");
+}
+
+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){
+               case MONO_CONSTANT_SUMMARIZED_VALUE:
+                       printf("Constant value: %d\n", value->value.constant);
+                       break;
+               case MONO_VARIABLE_SUMMARIZED_VALUE:
+                       printf("Variable value: %d\n", value->value.variable);
+                       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));
+                       }
+                       printf(")\n");
+                       break;
+               }
+               default:
+                       printf("Unknown value type: %d\n", value->value_type);
+       }
+}
+
+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);
+       }
+}
+
+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);
+       }
+}
+
+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++;
+               }
+       }
+       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 (relations->relation_with_one != MONO_ANY_RELATION){
+                       printf("relation_with_one: ");
+                       print_relation(relations->relation_with_one);
+                       printf("\n");
+               }
+               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");
+                               }
+                       }
+               }
+       }
+}
+
+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);
+       }
+}
+
+
+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 MonoInst *get_variable_value_from_ssa_store(MonoInst *store, int expected_variable_index)
+{
+       switch (store->opcode){
+               case CEE_STIND_REF:
+               case CEE_STIND_I:
+               case CEE_STIND_I4:
+               case CEE_STIND_I1:
+               case CEE_STIND_I2:
+               case CEE_STIND_I8:
+               case CEE_STIND_R4:
+               case CEE_STIND_R8:
+                       if (TRACE_ABC_REMOVAL) {
+                               printf("Store instruction found...\n");
+                       }
+                       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);
+                               }
+                               if (variable_index == expected_variable_index)
+                               {
+                                       return store->inst_right;
+                               }
+                               else
+                               {
+                                       return NULL;
+                               }
+                       }
+                       else
+                       {
+                               return NULL;
+                       }
+                       break;
+               default:
+                       return NULL;
+       }
+
+}
+
+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;
+                       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);
+                       }
+                       break;
+               }
+               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);
+                       }
+                       break;
+               }
+               case CEE_ADD:
+               case CEE_SUB: {
+                       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);
+                                       }
+                               } else {
+                                       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 {
+                                       MAKE_VALUE_ANY(result);
+                               }
+                       } else if (IS_SUMMARIZED_VALUE_CONSTANT(right_value)&& IS_SUMMARIZED_VALUE_CONSTANT(left_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;
+                               } else {
+                                       MAKE_VALUE_ANY(result);
+                               }
+                       } else {
+                               MAKE_VALUE_ANY(result);
+                       }
+                       break;
+               }
+               case CEE_NEWARR: {
+                       summarize_value(value->inst_newa_len, result);
+                       break;
+               }
+               case CEE_LDLEN: {
+                       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;
+                       break;
+               }
+               default: {
+                       MAKE_VALUE_ANY(result);
+               }
+       }
+}
+
+static MonoValueRelation get_relation_from_branch_instruction(int opcode){
+       switch (opcode){
+                       case CEE_BEQ:
+                               return MONO_EQ_RELATION;
+                       case CEE_BLT:
+                       case CEE_BLT_UN:
+                               return MONO_LT_RELATION;
+                       case CEE_BLE:
+                       case CEE_BLE_UN:
+                               return MONO_LE_RELATION;
+                       case CEE_BGT:
+                       case CEE_BGT_UN:
+                               return MONO_GT_RELATION;
+                       case CEE_BGE:
+                       case CEE_BGE_UN:
+                               return MONO_GE_RELATION;
+                       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;
+}
+
+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;
+       
+       if (TRACE_ABC_REMOVAL) {
+               printf("Analyzing block %d [dfn %d]\n", bb->block_num, bb->dfn);
+       }
+       
+       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){
+                                       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);
+                                       int number_of_variables = 0;
+                                       int current_variable = 0;
+                                       /* 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){
+                                                       b->number_of_branches = 2;
+                                                       b->branches = (MonoBranchData*) mono_mempool_alloc(
+                                                               evaluation_area->pool, sizeof(MonoBranchData) * 2);
+                                                       MonoBranchData *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);
+                                                       MonoBranchData *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]);
+                                                               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;
+                                                               MonoBranchCondition *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]);
+                                                               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;
+                                                               MonoBranchCondition *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;
+                                               }
+                                       } else {
+                                               b->number_of_branches = 0;
+                                               b->branches = NULL;
+                                       }
+                               } 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);
+       }
+}
+
+#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);
+
+#define RELATION_ASSIGNMENT(destination,source) (destination)=(source)
+#define RELATION_UNION(destination,source) (destination)|=(source)
+#define RELATION_INTERSECTION(destination,source) (destination)&=(source)
+
+
+
+static void evaluate_variable_relations(gssize variable, MonoVariableRelationsEvaluationArea *evaluation_area, MonoRelationsEvaluationContext *father_context){
+       if (TRACE_ABC_REMOVAL) {
+       printf("Applying definition of variable %d\n", variable);
+       }
+       MonoVariableRelations *relations = &(evaluation_area->variable_relations [variable]);
+       MonoRelationsEvaluationContext context;
+       context.father_context = father_context;
+       context.variable = variable;
+       switch (relations->evaluation_step) {
+               case MONO_RELATIONS_EVALUATION_NOT_STARTED: {
+                       MonoSummarizedValue *value = &(evaluation_area->variable_definitions [variable]);
+                       relations->evaluation_step = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
+                       if (TRACE_ABC_REMOVAL) {
+                               printf("Current step is MONO_RELATIONS_EVALUATION_NOT_STARTED, summarized value is:\n");
+                               print_summarized_value(value);
+                       }
+                       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);
+                                       }
+                                       /* Other cases should be handled... */
+                                       break;
+                               }
+                               case MONO_PHI_SUMMARIZED_VALUE: {
+                                       if (value->relation_with_value == MONO_EQ_RELATION){
+                                               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);
+                                               }
+                                               if (TRACE_ABC_REMOVAL) {
+                                                       printf("Resulting phi_union is:\n");
+                                                       print_variable_relations(phi_union, variable, evaluation_area->cfg->num_varinfo);
+                                               }
+                                               COMBINE_VARIABLE_RELATIONS(RELATION_INTERSECTION, relations,
+                                                       phi_union, evaluation_area->cfg->num_varinfo);
+                                       }
+                                       /* Other cases should not happen... */
+                                       break;
+                               }
+                               default: {
+                                       g_assert_not_reached();
+                               }
+                       }
+                       break;
+               }
+               case MONO_RELATIONS_EVALUATION_IN_PROGRESS: {
+                       if (TRACE_ABC_REMOVAL) {
+                               printf("Current step is MONO_RELATIONS_EVALUATION_IN_PROGRESS\n");
+                       }
+                       relations->definition_is_recursive = 1;
+                       MonoVariableRelations *recursive_value_relations = NULL;
+                       unsigned char recursive_relation = MONO_ANY_RELATION;
+                       MonoRelationsEvaluationContext *current_context = context.father_context;
+                       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);
+                               }
+                               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");
+                                               }
+                                       }
+                               } 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");
+                                               }
+                                       }
+                               }
+                               current_context = current_context->father_context;
+                       }
+                       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;
+                               }
+                       }
+                       return;
+               }
+               case MONO_RELATIONS_EVALUATION_COMPLETED: {
+                       if (TRACE_ABC_REMOVAL) {
+                               printf("Current step is MONO_RELATIONS_EVALUATION_COMPLETED\n");
+                       }
+                       return;
+               }
+               default: {
+                       g_assert_not_reached();
+               }
+       }
+       
+       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(" => ");
+                                       }
+                                       relations->relation_with_zero &= new_relation_with_zero;
+                                       if (TRACE_ABC_REMOVAL) {
+                                               print_relation(relations->relation_with_zero);
+                                               printf("\n");
+                                       }
+                                       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");
+                                               }
+                                               changes++;
+                                       }
+                               }
+                       }
+               }
+       }
+       return changes;
+}
+
+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));
+                               }
+                       }
+               }
+       }
+       
+       if (mono_burg_arity [inst->opcode]){
+               remove_abc_from_inst(inst->inst_left, evaluation_area);
+               if (mono_burg_arity [inst->opcode] > 1){
+                       remove_abc_from_inst(inst->inst_right, evaluation_area);
+               }
+       }
+}
+
+static void remove_abc_from_block(MonoSummarizedBasicBlock *b, MonoVariableRelationsEvaluationArea *evaluation_area){
+       int i;
+       int changes;
+       MonoBasicBlock *bb;
+       MonoInst *current_inst = b->block->code;
+       
+       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);
+       }
+       
+       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){
+                                               if (TRACE_ABC_REMOVAL) {
+                                                       printf("Applying conditions of branch %d -> %d\n", in_b->block->block_num, bb->block_num);
+                                               }
+                                               MonoBranchData *branch = &(in_b->branches [out_index]);
+                                               int condition_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);
+               }
+               
+               for (i = 0; i < evaluation_area->cfg->num_varinfo; i++){
+                       evaluate_variable_relations(i, evaluation_area, NULL);
+               }
+               
+               if (TRACE_ABC_REMOVAL) {
+                       printf("Variable definitions applied... ");
+                       print_all_variable_relations(evaluation_area);
+               }
+               
+               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);
+               }
+               
+               /* 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;
+               }
+       }
+}
+
+void
+mono_perform_abc_removal (MonoCompile *cfg)
+{
+       MonoVariableRelationsEvaluationArea evaluation_area;
+       int i;
+       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);
+       }
+       for (i = 0; i < cfg->num_varinfo; i++){
+               if (cfg->vars [i]->def != NULL)
+               {
+                       MonoInst *value = get_variable_value_from_ssa_store(cfg->vars [i]->def, i);
+                       if (value != NULL)
+                       {
+                               summarize_value(value, evaluation_area.variable_definitions + i);
+                               if (TRACE_ABC_REMOVAL) {
+                                       printf("Summarized variable %d\n", i);
+                                       print_summarized_value(evaluation_area.variable_definitions + i);
+                               }
+                       }
+                       else
+                       {
+                               MAKE_VALUE_ANY(evaluation_area.variable_definitions + i);
+                               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);
+                       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");
+               }
+               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);
+               }
+       }
+}
+
+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
diff --git a/mono/mini/abcremoval.h b/mono/mini/abcremoval.h
new file mode 100644 (file)
index 0000000..69b998e
--- /dev/null
@@ -0,0 +1,83 @@
+
+#include "mini.h"
+
+
+typedef enum {
+       MONO_EQ_RELATION = 1,
+       MONO_LT_RELATION = 2,
+       MONO_GT_RELATION = 4,
+       MONO_NE_RELATION = (MONO_LT_RELATION|MONO_GT_RELATION),
+       MONO_LE_RELATION = (MONO_LT_RELATION|MONO_EQ_RELATION),
+       MONO_GE_RELATION = (MONO_GT_RELATION|MONO_EQ_RELATION),
+       MONO_ANY_RELATION = (MONO_EQ_RELATION|MONO_LT_RELATION|MONO_GT_RELATION),
+       MONO_NO_RELATION = 0
+} MonoValueRelation;
+
+
+typedef enum {
+       MONO_CONSTANT_SUMMARIZED_VALUE = 0,
+       MONO_VARIABLE_SUMMARIZED_VALUE,
+       MONO_PHI_SUMMARIZED_VALUE
+} MonoSummarizedValueType;
+
+
+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;
+
+
+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;
+
+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;
+
+typedef struct MonoVariableRelationsEvaluationArea {
+       MonoCompile *cfg;
+       MonoMemPool *pool;
+       MonoVariableRelations *variable_relations;
+       MonoSummarizedValue *variable_definitions;
+       MonoSummarizedBasicBlock *blocks;
+} MonoVariableRelationsEvaluationArea;
+
+typedef struct MonoRelationsEvaluationContext {
+       struct MonoRelationsEvaluationContext *father_context;
+       gssize variable;
+} MonoRelationsEvaluationContext;
+
+extern void
+mono_perform_abc_removal (MonoCompile *cfg);
diff --git a/mono/mini/build_relations_propagation_table.pl b/mono/mini/build_relations_propagation_table.pl
new file mode 100755 (executable)
index 0000000..339ee32
--- /dev/null
@@ -0,0 +1,119 @@
+#!/usr/bin/perl
+
+@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;
index 6489fef899c982c1164de1ab03462b52455827b4..bb159ba29c2853413bd80b57df970014379a8cc3 100644 (file)
@@ -77,7 +77,8 @@ opt_names [] = {
        {"fcmov",    "Fast x86 FP compares"},
        {"leaf",     "Leaf procedures optimizations"},
        {"aot",      "Usage of Ahead Of Time compiled code"},
-       {"precomp",  "Precompile all methods before executing Main"}
+       {"precomp",  "Precompile all methods before executing Main"},
+       {"abcrem",   "Array bound checks removal"}
 };
 
 #define DEFAULT_OPTIMIZATIONS (        \
@@ -222,7 +223,8 @@ opt_sets [] = {
        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP,
        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_CFOLD,
        MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE,
-       MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS
+       MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS,
+       MONO_OPT_BRANCH | MONO_OPT_PEEPHOLE | MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP | MONO_OPT_DEADCE | MONO_OPT_LOOP | MONO_OPT_INLINE | MONO_OPT_INTRINS | MONO_OPT_ABCREM
 };
 
 typedef int (*TestMethod) (void);
index c3646e8632589627470b6449e4d7277015b6bac2..e0bc1f0254b165b55cf4d4a939468848df685173 100644 (file)
        } while (0)
 
 #define MONO_EMIT_BOUNDS_CHECK(cfg, array_reg, array_type, array_length_field, index_reg) do { \
-               int _length_reg = mono_regstate_next_int (cfg->rs); \
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, _length_reg, array_reg, G_STRUCT_OFFSET (array_type, array_length_field)); \
-               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, _length_reg, index_reg); \
-               MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
+               if (! (state->tree->flags & MONO_INST_NORANGECHECK)) { \
+                       int _length_reg = mono_regstate_next_int (cfg->rs); \
+                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, _length_reg, array_reg, G_STRUCT_OFFSET (array_type, array_length_field)); \
+                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, _length_reg, index_reg); \
+                       MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
+               } \
        } while (0)
 
 #define MONO_EMIT_BOUNDS_CHECK_IMM(cfg, array_reg, array_type, array_length_field, index_imm) do { \
-               int _length_reg = mono_regstate_next_int (cfg->rs); \
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, _length_reg, array_reg, G_STRUCT_OFFSET (array_type, array_length_field)); \
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, _length_reg, index_imm); \
-               MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
+               if (! (state->tree->flags & MONO_INST_NORANGECHECK)) { \
+                       int _length_reg = mono_regstate_next_int (cfg->rs); \
+                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, _length_reg, array_reg, G_STRUCT_OFFSET (array_type, array_length_field)); \
+                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, _length_reg, index_imm); \
+                       MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
+               } \
        } while (0)
 
 /* we need to kludge state because monoburg puts this stuff before the definition of MBState */
index 43e91f27893b15f620e6d4aca230427f3e603351..b882977988dc961cb3def999d4ad5f4b8024a8ff 100644 (file)
@@ -48,6 +48,7 @@
 #include "inssel.h"
 #include "trace.h"
 
+#include "abcremoval.h"
 #include "jit-icalls.c"
 
 #define MONO_IS_COND_BRANCH(op) ((op >= CEE_BEQ && op <= CEE_BLT_UN) || (op >= OP_LBEQ && op <= OP_LBLT_UN) || (op >= OP_FBEQ && op <= OP_FBLT_UN))
@@ -7805,7 +7806,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 #else 
 
        /* fixme: add all optimizations which requires SSA */
-       if (cfg->opt & (MONO_OPT_DEADCE)) {
+       if ((cfg->opt & (MONO_OPT_DEADCE)) || (cfg->opt & (MONO_OPT_ABCREM))) {
                if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
                        mono_local_cprop (cfg);
                        mono_ssa_compute (cfg);
@@ -7834,6 +7835,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
                //mono_ssa_strength_reduction (cfg);
 
+               if (cfg->opt & MONO_OPT_ABCREM)
+               {
+                       mono_perform_abc_removal (cfg);
+               }
+
                mono_ssa_remove (cfg);
 
                if (cfg->opt & MONO_OPT_BRANCH)
index 0c52aa724f661abdf8c16390f7a814c7853c2358..803d01e2e8cf03e825a1a66e02ad21e8f8587e9e 100644 (file)
@@ -450,7 +450,8 @@ enum {
        MONO_OPT_FCMOV    = 1 << 14,
        MONO_OPT_LEAF     = 1 << 15,
        MONO_OPT_AOT      = 1 << 16,
-       MONO_OPT_PRECOMP  = 1 << 17
+       MONO_OPT_PRECOMP  = 1 << 17,
+       MONO_OPT_ABCREM   = 1 << 18
 };
 
 /* Bit-fields in the MonoBasicBlock.region */
diff --git a/mono/mini/propagated_relations_table.def b/mono/mini/propagated_relations_table.def
new file mode 100644 (file)
index 0000000..93297a3
--- /dev/null
@@ -0,0 +1,64 @@
+  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 */