#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/mempool.h>
#include <mono/metadata/opcodes.h>
+#include <mono/metadata/mempool-internals.h>
+
+#include <config.h>
#ifndef DISABLE_JIT
}
#endif
-static inline GSList*
-g_slist_append_mempool (MonoMemPool *mp, GSList *list, gpointer data)
-{
- GSList *new_list;
- GSList *last;
-
- new_list = mono_mempool_alloc (mp, sizeof (GSList));
- new_list->data = data;
- new_list->next = NULL;
-
- if (list) {
- last = list;
- while (last->next)
- last = last->next;
- last->next = new_list;
-
- return list;
- } else
- return new_list;
-}
-
/*
* Check if the delta of an integer variable value is safe with respect
* to the variable size in bytes and its kind (signed or unsigned).
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);
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;
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 */
default:
+ /* These opcodes are not currently handled while running SciMark, first
+ * column is the number of times the warning was shown:
+ *
+ * 1 add_imm
+ * 1 float_conv_to_i8
+ * 1 int_mul_ovf_un
+ * 1 int_neg
+ * 1 int_or
+ * 1 int_shr_un
+ * 1 localloc
+ * 1 long_ceq
+ * 1 long_rem
+ * 1 long_sub
+ * 2 int_ceq
+ * 2 int_conv_to_i2
+ * 2 int_min
+ * 2 lcall
+ * 2 long_div
+ * 3 int_conv_to_u2
+ * 3 long_shr_imm
+ * 4 int_rem
+ * 4 int_rem_imm
+ * 4 loadi1_membase
+ * 4 loadu4_membase
+ * 5 int_div
+ * 5 shl_imm
+ * 6 int_div_imm
+ * 6 int_mul
+ * 9 int_mul_imm
+ * 9 zext_i4
+ * 10 int_shr_imm
+ * 12 int_shr_un_imm
+ * 12 long_add_imm
+ * 12 outarg_vtretaddr
+ * 12 strlen
+ * 13 int_or_imm
+ * 23 call_membase
+ * 23 int_conv_to_u1
+ * 23 long_add
+ * 24 int_and_imm
+ * 24 int_shl_imm
+ * 24 loadu2_membase
+ * 29 loadi8_membase
+ * 31 llvm_outarg_vt
+ * 34 int_sub
+ * 34 loadu1_membase
+ * 42 int_add
+ * 85 ldaddr
+ * 116 loadi4_membase
+ * 159 x86_lea
+ * 179 sext_i4
+ * 291 load_membase
+ * 462 i8const
+ * 472 call
+ */
+
break;
}
return value_kind;
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) {
}
}
+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 = 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):
printf ("\nProcessing block %d [dfn %d]...\n", bb->block_num, bb->dfn);
}
+ if (bb->region != -1)
+ return;
+
get_relations_from_previous_bb (area, bb, &additional_relations);
if (TRACE_ABC_REMOVAL) {
if (additional_relations.relation1.relation.relation != MONO_ANY_RELATION) {
}
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);
+ }
+ */
}
}
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 = 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) {