Merge pull request #2854 from alexrp/lock-free-queue-docs
[mono.git] / mono / mini / abcremoval.c
index a8082d1cebd0095e7141b59b5814f0723b92942c..fddbef9d9cb64556dc4f726d1adfb3a5a9260bce 100644 (file)
@@ -62,8 +62,8 @@ static int verbose_level;
                (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 MONO_NEGATED_RELATION(r) ((MonoValueRelation)((~(r))&MONO_ANY_RELATION))
+#define MONO_SYMMETRIC_RELATION(r) ((MonoValueRelation)(((r)&MONO_EQ_RELATION)|(((r)&MONO_LT_RELATION)<<1)|((r&MONO_GT_RELATION)>>1)))
 
 
 
@@ -275,6 +275,12 @@ get_relation_from_ins (MonoVariableRelationsEvaluationArea *area, MonoInst *ins,
                value->value.variable.variable = ins->sreg1;
                value->value.variable.delta = 0;
                break;
+       case OP_SEXT_I4:
+               value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
+               value->value.variable.variable = ins->sreg1;
+               value->value.variable.delta = 0;
+               value_kind = MONO_INTEGER_VALUE_SIZE_8;
+               break;
        case OP_PHI:
                value->type = MONO_PHI_SUMMARIZED_VALUE;
                value->value.phi.number_of_alternatives = *(ins->inst_phi_args);
@@ -290,7 +296,7 @@ get_relation_from_ins (MonoVariableRelationsEvaluationArea *area, MonoInst *ins,
        case OP_ISUB_IMM:
                value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
                value->value.variable.variable = ins->sreg1;
-               value->value.variable.delta = ins->inst_imm;
+               value->value.variable.delta = -ins->inst_imm;
                /* FIXME: */
                //check_delta_safety (area, result);
                break;
@@ -316,6 +322,13 @@ get_relation_from_ins (MonoVariableRelationsEvaluationArea *area, MonoInst *ins,
                value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
                value->value.variable.variable = ins->sreg1;
                value->value.variable.delta = 0;
+               area->defs [ins->dreg] = ins;
+               break;
+       case OP_LDADDR:
+               /* The result is non-null */
+               result->relation = MONO_GT_RELATION;
+               value->type = MONO_CONSTANT_SUMMARIZED_VALUE;
+               value->value.constant.value = 0;
                break;
 
                /* FIXME: Add more opcodes */
@@ -892,7 +905,7 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are
                        
                        current_context = father_context;
                        while (current_context != last_context) {
-                               current_context->status |= recursive_status;
+                               current_context->status = (MonoRelationsEvaluationStatus)(current_context->status | recursive_status);
                                current_context = current_context->father;
                        }
                } else {
@@ -982,8 +995,8 @@ remove_abc_from_inst (MonoInst *ins, MonoVariableRelationsEvaluationArea *area)
                if (REPORT_ABC_REMOVAL) {
                        printf ("ARRAY-ACCESS: removed bounds check on array %d with index %d\n",
                                        array_variable, index_variable);
-                       NULLIFY_INS (ins);
                }
+               NULLIFY_INS (ins);
        } else {
                if (TRACE_ABC_REMOVAL) {
                        if (index_context->ranges.zero.lower >= 0) {
@@ -999,6 +1012,34 @@ remove_abc_from_inst (MonoInst *ins, MonoVariableRelationsEvaluationArea *area)
        }
 }
 
+static gboolean
+eval_non_null (MonoVariableRelationsEvaluationArea *area, int reg)
+{
+       MonoRelationsEvaluationContext *context = &(area->contexts [reg]);
+
+       clean_contexts (area->contexts, area->cfg->next_vreg);
+       evaluate_relation_with_target_variable (area, reg, reg, NULL);
+                               
+       return context->ranges.zero.lower > 0;
+}
+
+static void
+add_non_null (MonoVariableRelationsEvaluationArea *area, MonoCompile *cfg, int reg,
+                         GSList **check_relations)
+{
+       MonoAdditionalVariableRelation *rel;
+
+       rel = (MonoAdditionalVariableRelation *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoAdditionalVariableRelation));
+       rel->variable = reg;
+       rel->relation.relation = MONO_GT_RELATION;
+       rel->relation.related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
+       rel->relation.related_value.value.constant.value = 0;
+
+       apply_change_to_evaluation_area (area, rel);
+
+       *check_relations = g_slist_append_mempool (cfg->mempool, *check_relations, rel);
+}
+
 /*
  * Process a BB removing bounds checks from array accesses.
  * It does the following (in sequence):
@@ -1065,7 +1106,7 @@ process_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoVariableRelationsEvalua
 
                        /* We can derive additional relations from the bounds check */
                        if (ins->opcode != OP_NOP) {
-                               rel = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoAdditionalVariableRelation));
+                               rel = (MonoAdditionalVariableRelation *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoAdditionalVariableRelation));
                                rel->variable = index_var;
                                rel->relation.relation = MONO_LT_RELATION;
                                rel->relation.related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
@@ -1076,7 +1117,7 @@ process_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoVariableRelationsEvalua
 
                                check_relations = g_slist_append_mempool (cfg->mempool, check_relations, rel);
 
-                               rel = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoAdditionalVariableRelation));
+                               rel = (MonoAdditionalVariableRelation *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoAdditionalVariableRelation));
                                rel->variable = index_var;
                                rel->relation.relation = MONO_GE_RELATION;
                                rel->relation.related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
@@ -1089,28 +1130,57 @@ process_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoVariableRelationsEvalua
                }
 
                if (ins->opcode == OP_CHECK_THIS) {
-                       MonoRelationsEvaluationContext *context = &(area->contexts [ins->sreg1]);
-
-                       clean_contexts (area->contexts, area->cfg->next_vreg);
-                       evaluate_relation_with_target_variable (area, ins->sreg1, ins->sreg1, NULL);
-                               
-                       if (context->ranges.zero.lower > 0) {
+                       if (eval_non_null (area, ins->sreg1)) {
                                if (REPORT_ABC_REMOVAL)
                                        printf ("ARRAY-ACCESS: removed check_this instruction.\n");
                                NULLIFY_INS (ins);
                        }
                }
 
-               if (ins->opcode == OP_NOT_NULL) {
-                       rel = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoAdditionalVariableRelation));
-                       rel->variable = ins->sreg1;
-                       rel->relation.relation = MONO_GT_RELATION;
-                       rel->relation.related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
-                       rel->relation.related_value.value.constant.value = 0;
-
-                       apply_change_to_evaluation_area (area, rel);
+               if (ins->opcode == OP_NOT_NULL)
+                       add_non_null (area, cfg, ins->sreg1, &check_relations);
 
-                       check_relations = g_slist_append_mempool (cfg->mempool, check_relations, rel);
+               /* 
+                * FIXME: abcrem equates an array with its length,
+                * so a = new int [100] implies a != null, but a = new int [0] doesn't.
+                */
+               /*
+                * Eliminate MONO_INST_FAULT flags if possible.
+                */
+               if (COMPILE_LLVM (cfg) && (ins->opcode == OP_LDLEN ||
+                                                                  ins->opcode == OP_BOUNDS_CHECK ||
+                                                                  ins->opcode == OP_STRLEN ||
+                                                                  (MONO_IS_LOAD_MEMBASE (ins) && (ins->flags & MONO_INST_FAULT)) ||
+                                                                  (MONO_IS_STORE_MEMBASE (ins) && (ins->flags & MONO_INST_FAULT)))) {
+                       int reg;
+
+                       if (MONO_IS_STORE_MEMBASE (ins))
+                               reg = ins->inst_destbasereg;
+                       else if (MONO_IS_LOAD_MEMBASE (ins))
+                               reg = ins->inst_basereg;
+                       else
+                               reg = ins->sreg1;
+
+                       /*
+                        * This doesn't work because LLVM can move the non-faulting loads before the faulting
+                        * ones (test_0_llvm_moving_faulting_loads ()).
+                        * So only do it if we know the load cannot be moved before the instruction which ensures it is not
+                        * null (i.e. the def of its sreg).
+                        */
+                       if (area->defs [reg] && area->defs [reg]->opcode == OP_NEWARR) {
+                               if (REPORT_ABC_REMOVAL)
+                                       printf ("ARRAY-ACCESS: removed MONO_INST_FAULT flag.\n");
+                               ins->flags &= ~MONO_INST_FAULT;
+                       }
+                       /*
+                       if (eval_non_null (area, reg)) {
+                               if (REPORT_ABC_REMOVAL)
+                                       printf ("ARRAY-ACCESS: removed MONO_INST_FAULT flag.\n");
+                               ins->flags &= ~MONO_INST_FAULT;
+                       } else {
+                               add_non_null (area, cfg, reg, &check_relations);
+                       }
+                       */
                }
        }       
        
@@ -1123,7 +1193,7 @@ process_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoVariableRelationsEvalua
        }
 
        for (l = check_relations; l; l = l->next)
-               remove_change_from_evaluation_area (l->data);
+               remove_change_from_evaluation_area ((MonoAdditionalVariableRelation *)l->data);
        
        remove_change_from_evaluation_area (&(additional_relations.relation1));
        remove_change_from_evaluation_area (&(additional_relations.relation2));
@@ -1154,10 +1224,10 @@ type_to_value_kind (MonoType *type)
                return MONO_UNSIGNED_INTEGER_VALUE_SIZE_4;
                break;
        case MONO_TYPE_I:
-               return SIZEOF_VOID_P;
+               return (MonoIntegerValueKind)SIZEOF_VOID_P;
                break;
        case MONO_TYPE_U:
-               return (MONO_UNSIGNED_VALUE_FLAG|SIZEOF_VOID_P);
+               return (MonoIntegerValueKind)(MONO_UNSIGNED_VALUE_FLAG | SIZEOF_VOID_P);
                break;
        case MONO_TYPE_I8:
                return MONO_INTEGER_VALUE_SIZE_8;
@@ -1205,12 +1275,14 @@ mono_perform_abc_removal (MonoCompile *cfg)
                mono_mempool_alloc (cfg->mempool, sizeof (MonoRelationsEvaluationContext) * (cfg->next_vreg));
        area.variable_value_kind = (MonoIntegerValueKind *)
                mono_mempool_alloc (cfg->mempool, sizeof (MonoIntegerValueKind) * (cfg->next_vreg));
+       area.defs = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * cfg->next_vreg);
        for (i = 0; i < cfg->next_vreg; i++) {
                area.variable_value_kind [i] = MONO_UNKNOWN_INTEGER_VALUE;
                area.relations [i].relation = MONO_EQ_RELATION;
                area.relations [i].relation_is_static_definition = TRUE;
                MAKE_VALUE_ANY (area.relations [i].related_value);
                area.relations [i].next = NULL;
+               area.defs [i] = NULL;
        }
 
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {