Xamarin Public Jenkins (auto-signing) e46a49ecf1 Imported Upstream version 5.10.0.47
Former-commit-id: d0813289fa2d35e1f8ed77530acb4fb1df441bc0
2018-01-24 17:04:36 +00:00

1403 lines
47 KiB
C

/**
* \file
* Array bounds check removal
*
* Author:
* Massimiliano Mantione (massi@ximian.com)
*
* (C) 2004 Ximian, Inc. http://www.ximian.com
*/
#include <config.h>
#include <string.h>
#include <stdio.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/mempool.h>
#include <mono/metadata/opcodes.h>
#include <mono/metadata/mempool-internals.h>
#include <mono/utils/mono-compiler.h>
#include <config.h>
#ifndef DISABLE_JIT
#include "abcremoval.h"
#if SIZEOF_VOID_P == 8
#define OP_PCONST OP_I8CONST
#else
#define OP_PCONST OP_ICONST
#endif
#define TRACE_ABC_REMOVAL (verbose_level > 2)
#define REPORT_ABC_REMOVAL (verbose_level > 1)
/*
* A little hack for the verbosity level.
* The verbosity level is stored in the cfg, but not all functions that must
* print something see the cfg, so we store the verbosity level here at the
* beginning of the algorithm.
* This is not thread safe (does not handle correctly different verbosity
* levels in different threads), and is not exact in case of dynamic changes
* of the verbosity level...
* Anyway, this is not needed, all that can happen is that something more
* (or less) is logged, the result is in any case correct.
*/
static int verbose_level;
#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).type = MONO_ANY_SUMMARIZED_VALUE;\
} while (0)
#define MAKE_VALUE_RELATION_ANY(r) do{\
(r)->relation = MONO_ANY_RELATION;\
MAKE_VALUE_ANY((r)->related_value);\
} while (0)
#define INITIALIZE_VALUE_RELATION(r) do{\
MAKE_VALUE_RELATION_ANY((r));\
(r)->next = NULL;\
} while (0)
#define MONO_NEGATED_RELATION(r) ((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)))
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) {
switch (value->type) {
case MONO_ANY_SUMMARIZED_VALUE:
printf ("ANY");
break;
case MONO_CONSTANT_SUMMARIZED_VALUE:
printf ("CONSTANT %d", value->value.constant.value);
break;
case MONO_VARIABLE_SUMMARIZED_VALUE:
printf ("VARIABLE %d, delta %d", value->value.variable.variable, value->value.variable.delta);
break;
case MONO_PHI_SUMMARIZED_VALUE: {
int phi;
printf ("PHI (");
for (phi = 0; phi < value->value.phi.number_of_alternatives; phi++) {
if (phi) printf (",");
printf ("%d", value->value.phi.phi_alternatives [phi]);
}
printf (")");
break;
}
default:
g_assert_not_reached ();
}
}
static void
print_summarized_value_relation (MonoSummarizedValueRelation *relation) {
printf ("Relation ");
print_relation (relation->relation);
printf (" with value ");
print_summarized_value (&(relation->related_value));
}
#if 0
static void
print_summarized_value_relation_chain (MonoSummarizedValueRelation *relation) {
printf ("Relations:\n");
while (relation) {
print_summarized_value_relation (relation);
printf ("\n");
relation = relation->next;
}
}
#endif
static void
print_evaluation_context_status (MonoRelationsEvaluationStatus status) {
if (status == MONO_RELATIONS_EVALUATION_NOT_STARTED) {
printf ("EVALUATION_NOT_STARTED");
} else {
gboolean print_or = FALSE;
printf ("(");
if (status & MONO_RELATIONS_EVALUATION_IN_PROGRESS) {
if (print_or) printf ("|");
printf ("EVALUATION_IN_PROGRESS");
print_or = TRUE;
}
if (status & MONO_RELATIONS_EVALUATION_COMPLETED) {
if (print_or) printf ("|");
printf ("EVALUATION_COMPLETED");
print_or = TRUE;
}
if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING) {
if (print_or) printf ("|");
printf ("RECURSIVELY_ASCENDING");
print_or = TRUE;
}
if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING) {
if (print_or) printf ("|");
printf ("RECURSIVELY_DESCENDING");
print_or = TRUE;
}
if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE) {
if (print_or) printf ("|");
printf ("RECURSIVELY_INDEFINITE");
print_or = TRUE;
}
printf (")");
}
}
static void
print_evaluation_context_ranges (MonoRelationsEvaluationRanges *ranges) {
printf ("(ranges: zero [%d,%d], variable [%d,%d])", ranges->zero.lower, ranges->zero.upper, ranges->variable.lower, ranges->variable.upper);
}
static void
print_evaluation_context (MonoRelationsEvaluationContext *context, MonoRelationsEvaluationStatus status) {
print_evaluation_context_status (status);
if (status & (MONO_RELATIONS_EVALUATION_IN_PROGRESS|MONO_RELATIONS_EVALUATION_COMPLETED)) {
print_evaluation_context_ranges (&(context->ranges));
}
printf ("\n");
}
#if 0
static void
print_evaluation_area (MonoVariableRelationsEvaluationArea *area) {
int i;
printf ("Dump of evaluation area (%d variables):\n", area->cfg->num_varinfo);
for (i = 0; i < area->cfg->num_varinfo; i++) {
printf ("Variable %d: ", i);
print_evaluation_context (&(area->contexts [i]));
print_summarized_value_relation_chain (&(area->relations [i]));
}
}
static void
print_evaluation_area_contexts (MonoVariableRelationsEvaluationArea *area) {
int i;
printf ("Dump of evaluation area contexts (%d variables):\n", area->cfg->num_varinfo);
for (i = 0; i < area->cfg->num_varinfo; i++) {
printf ("Variable %d: ", i);
print_evaluation_context (&(area->contexts [i]));
}
}
#endif
/*
* 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).
* If the delta is not safe, make the value an "any".
*/
static G_GNUC_UNUSED void
check_delta_safety (MonoVariableRelationsEvaluationArea *area, MonoSummarizedValue *value) {
if (value->type == MONO_VARIABLE_SUMMARIZED_VALUE) {
int variable = value->value.variable.variable;
int delta = value->value.variable.delta;
if ((area->variable_value_kind [variable]) & MONO_UNSIGNED_VALUE_FLAG) {
if (delta < 0) {
MAKE_VALUE_ANY (*value);
}
} else {
if (((area->variable_value_kind [variable]) & MONO_INTEGER_VALUE_SIZE_BITMASK) < 4) {
MAKE_VALUE_ANY (*value);
} else if (delta > 16) {
MAKE_VALUE_ANY (*value);
}
}
}
}
/*
* get_relation_from_ins:
*
* Obtain relations from a MonoInst.
*
* result_value_kind: the "expected" kind of result;
* result: the "summarized" value
* returns the "actual" kind of result, if guessable (otherwise MONO_UNKNOWN_INTEGER_VALUE)
*/
static MonoIntegerValueKind
get_relation_from_ins (MonoVariableRelationsEvaluationArea *area, MonoInst *ins, MonoSummarizedValueRelation *result, MonoIntegerValueKind result_value_kind)
{
MonoIntegerValueKind value_kind;
MonoSummarizedValue *value = &result->related_value;
if (ins->type == STACK_I8) {
value_kind = MONO_INTEGER_VALUE_SIZE_8;
} else if (ins->type == STACK_I4) {
value_kind = MONO_INTEGER_VALUE_SIZE_4;
} else {
value_kind = MONO_UNKNOWN_INTEGER_VALUE;
}
result->relation = MONO_EQ_RELATION;
MAKE_VALUE_ANY (*value);
switch (ins->opcode) {
case OP_ICONST:
value->type = MONO_CONSTANT_SUMMARIZED_VALUE;
value->value.constant.value = ins->inst_c0;
break;
case OP_MOVE:
value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
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);
value->value.phi.phi_alternatives = ins->inst_phi_args + 1;
break;
case OP_IADD_IMM:
value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
value->value.variable.variable = ins->sreg1;
value->value.variable.delta = ins->inst_imm;
/* FIXME: */
//check_delta_safety (area, result);
break;
case OP_ISUB_IMM:
value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
value->value.variable.variable = ins->sreg1;
value->value.variable.delta = -ins->inst_imm;
/* FIXME: */
//check_delta_safety (area, result);
break;
case OP_IREM_UN:
/* The result of an unsigned remainder is 0 < x < the divisor */
result->relation = MONO_LT_RELATION;
value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
value->value.variable.variable = ins->sreg2;
value->value.variable.delta = 0;
value_kind = MONO_UNSIGNED_INTEGER_VALUE_SIZE_4;
break;
case OP_LDLEN:
/*
* We represent arrays by their length, so r1<-ldlen r2 is stored
* as r1 == r2 in the evaluation graph.
*/
value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
value->value.variable.variable = ins->sreg1;
value->value.variable.delta = 0;
value_kind = MONO_UNSIGNED_INTEGER_VALUE_SIZE_4;
break;
case OP_NEWARR:
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;
}
static MonoValueRelation
get_relation_from_branch_instruction (MonoInst *ins)
{
if (MONO_IS_COND_BRANCH_OP (ins)) {
CompRelation rel = mono_opcode_to_cond (ins->opcode);
switch (rel) {
case CMP_EQ:
return MONO_EQ_RELATION;
case CMP_NE:
return MONO_NE_RELATION;
case CMP_LE:
case CMP_LE_UN:
return MONO_LE_RELATION;
case CMP_GE:
case CMP_GE_UN:
return MONO_GE_RELATION;
case CMP_LT:
case CMP_LT_UN:
return MONO_LT_RELATION;
case CMP_GT:
case CMP_GT_UN:
return MONO_GT_RELATION;
default:
g_assert_not_reached ();
return MONO_ANY_RELATION;
}
} else {
return MONO_ANY_RELATION;
}
}
/*
* Given a BB, find its entry condition and put its relations in a
* "MonoAdditionalVariableRelationsForBB" structure.
* bb: the BB
* relations: the resulting relations (entry condition of the given BB)
*/
static void
get_relations_from_previous_bb (MonoVariableRelationsEvaluationArea *area, MonoBasicBlock *bb, MonoAdditionalVariableRelationsForBB *relations)
{
MonoBasicBlock *in_bb;
MonoInst *ins, *compare, *branch;
MonoValueRelation branch_relation;
MonoValueRelation symmetric_relation;
gboolean code_path;
INITIALIZE_VALUE_RELATION (&(relations->relation1.relation));
relations->relation1.relation.relation_is_static_definition = FALSE;
relations->relation1.relation.next = NULL;
relations->relation1.insertion_point = NULL;
relations->relation1.variable = -1;
INITIALIZE_VALUE_RELATION (&(relations->relation2.relation));
relations->relation2.relation.relation_is_static_definition = FALSE;
relations->relation2.relation.next = NULL;
relations->relation2.insertion_point = NULL;
relations->relation2.variable = -1;
if (bb->in_count == 1) { /* Should write the code to "sum" conditions... */
in_bb = bb->in_bb [0];
if ((in_bb->last_ins == NULL) || (in_bb->code == in_bb->last_ins))
return;
for (ins = in_bb->code; ins->next != in_bb->last_ins; ins = ins->next)
;
compare = ins;
branch = ins->next;
branch_relation = get_relation_from_branch_instruction (branch);
if (branch_relation != MONO_ANY_RELATION) {
if (branch->inst_true_bb == bb) {
code_path = TRUE;
} else if (branch->inst_false_bb == bb) {
code_path = FALSE;
} else {
code_path = TRUE;
g_assert_not_reached ();
}
if (!code_path)
branch_relation = MONO_NEGATED_RELATION (branch_relation);
symmetric_relation = MONO_SYMMETRIC_RELATION (branch_relation);
/* FIXME: Other compare opcodes */
if (compare->opcode == OP_ICOMPARE) {
relations->relation1.variable = compare->sreg1;
relations->relation1.relation.relation = branch_relation;
relations->relation1.relation.related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
relations->relation1.relation.related_value.value.variable.variable = compare->sreg2;
relations->relation1.relation.related_value.value.variable.delta = 0;
relations->relation2.variable = compare->sreg2;
relations->relation2.relation.relation = symmetric_relation;
relations->relation2.relation.related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
relations->relation2.relation.related_value.value.variable.variable = compare->sreg1;
relations->relation2.relation.related_value.value.variable.delta = 0;
} else if (compare->opcode == OP_ICOMPARE_IMM) {
relations->relation1.variable = compare->sreg1;
relations->relation1.relation.relation = branch_relation;
relations->relation1.relation.related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
relations->relation1.relation.related_value.value.constant.value = compare->inst_imm;
}
}
}
}
/*
* Add the given relations to the evaluation area.
* area: the evaluation area
* change: the relations that must be added
*/
static void
apply_change_to_evaluation_area (MonoVariableRelationsEvaluationArea *area, MonoAdditionalVariableRelation *change)
{
MonoSummarizedValueRelation *base_relation;
if (change->relation.relation != MONO_ANY_RELATION) {
base_relation = &(area->relations [change->variable]);
while ((base_relation->next != NULL) && (base_relation->next->relation_is_static_definition)) {
base_relation = base_relation->next;
}
change->insertion_point = base_relation;
change->relation.next = base_relation->next;
base_relation->next = &(change->relation);
}
}
/*
* Remove the given relation from the evaluation area.
* change: the relation that must be removed
*/
static void
remove_change_from_evaluation_area (MonoAdditionalVariableRelation *change)
{
if (change->insertion_point != NULL) {
change->insertion_point->next = change->relation.next;
change->relation.next = NULL;
}
}
static void
clean_contexts (MonoVariableRelationsEvaluationArea *area, int number)
{
memset(area->statuses, MONO_RELATIONS_EVALUATION_NOT_STARTED, number * sizeof(MonoRelationsEvaluationStatus));
}
/*
* Perform the intersection of a range and a constant value (taking into
* account the relation that the value has with the range).
* range: the range that will be intersected with the value
* value: the value that will be intersected with the range
* relation: the relation between the range and the value
*/
static void
intersect_value( MonoRelationsEvaluationRange *range, int value, MonoValueRelation relation )
{
switch (relation) {
case MONO_NO_RELATION:
MONO_MAKE_RELATIONS_EVALUATION_RANGE_IMPOSSIBLE (*range);
break;
case MONO_ANY_RELATION:
break;
case MONO_EQ_RELATION:
MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, value);
MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, value);
break;
case MONO_NE_RELATION: {
/* IMPROVEMENT Figure this out! (ignoring it is safe anyway) */
break;
}
case MONO_LT_RELATION:
MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (value));
break;
case MONO_LE_RELATION:
MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, value);
break;
case MONO_GT_RELATION:
MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (value));
break;
case MONO_GE_RELATION:
MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, value);
break;
default:
g_assert_not_reached();
}
}
/*
* Perform the intersection of two pairs of ranges (taking into account the
* relation between the ranges and a given delta).
* ranges: the ranges that will be intersected
* other_ranges the other ranges that will be intersected
* delta: the delta between the pairs of ranges
* relation: the relation between the pairs of ranges
*/
static void
intersect_ranges( MonoRelationsEvaluationRanges *ranges, MonoRelationsEvaluationRanges *other_ranges, int delta, MonoValueRelation relation )
{
if (delta == 0) {
switch (relation) {
case MONO_NO_RELATION:
MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (*ranges);
break;
case MONO_ANY_RELATION:
break;
case MONO_EQ_RELATION:
MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (*ranges, *other_ranges);
break;
case MONO_NE_RELATION: {
/* FIXME Figure this out! (ignoring it is safe anyway) */
break;
}
case MONO_LT_RELATION:
MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->zero.upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->zero.upper));
MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->variable.upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->variable.upper));
break;
case MONO_LE_RELATION:
MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->zero.upper, other_ranges->zero.upper);
MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->variable.upper, other_ranges->variable.upper);
break;
case MONO_GT_RELATION:
MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->zero.lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->zero.lower));
MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->variable.lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->variable.lower));
break;
case MONO_GE_RELATION:
MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->zero.lower, other_ranges->zero.lower);
MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->variable.lower, other_ranges->variable.lower);
break;
default:
g_assert_not_reached();
}
} else {
MonoRelationsEvaluationRanges translated_ranges = *other_ranges;
MONO_ADD_DELTA_SAFELY_TO_RANGES (translated_ranges, delta);
intersect_ranges( ranges, &translated_ranges, FALSE, relation );
}
}
/*
* Recursive method that traverses the relation graph to evaluate the
* relation between two variables.
* At the end of the execution, the resulting ranges are in the context of
* the "starting" variable.
* area: the current evaluation area (it contains the relation graph and
* memory for all the evaluation contexts is already allocated)
* variable: starting variable (the value ranges in its context are the result
* of the execution of this procedure)
* target_variable: the variable with respect to which the starting variable
* is evaluated (tipically the starting variable is the index
* and the target one is the array (which means its length))
* father_context: the previous evaluation context in recursive invocations
* (or NULL for the first invocation)
*/
static void
evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *area, const int variable, const int target_variable, MonoRelationsEvaluationContext *father_context)
{
MonoRelationsEvaluationContext * const context = &(area->contexts [variable]);
MonoRelationsEvaluationStatus * const status = &(area->statuses [variable]);
// First of all, we check the evaluation status
// (what must be done is *very* different in each case)
switch (*status) {
case MONO_RELATIONS_EVALUATION_NOT_STARTED: {
MonoSummarizedValueRelation *relation = &(area->relations [variable]);
if (TRACE_ABC_REMOVAL) {
printf ("Evaluating variable %d (target variable %d)\n", variable, target_variable);
print_summarized_value_relation (relation);
printf ("\n");
}
// We properly inizialize the context
*status = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
context->father = father_context;
MONO_MAKE_RELATIONS_EVALUATION_RANGES_WEAK (context->ranges);
// If we have found the target variable, we can set the range
// related to it in the context to "equal" (which is [0,0])
if (variable == target_variable) {
if (TRACE_ABC_REMOVAL) {
printf ("Target variable reached (%d), continuing to evaluate relations with constants\n", variable);
}
context->ranges.variable.lower = 0;
context->ranges.variable.upper = 0;
}
// Examine all relations for this variable (scan the list)
// The contribute of each relation will be intersected (logical and)
while (relation != NULL) {
context->current_relation = relation;
if (TRACE_ABC_REMOVAL) {
printf ("Processing (%d): ", variable);
print_summarized_value_relation (relation);
printf ("\n");
}
// We decie what to do according the the type of the related value
switch (relation->related_value.type) {
case MONO_ANY_SUMMARIZED_VALUE:
// No added information, skip it
break;
case MONO_CONSTANT_SUMMARIZED_VALUE:
// Intersect range with constant (taking into account the relation)
intersect_value (&(context->ranges.zero), relation->related_value.value.constant.value, relation->relation);
break;
case MONO_VARIABLE_SUMMARIZED_VALUE:
// Generally, evaluate related variable and intersect ranges.
// However, some check is necessary...
// If the relation is "ANY", nothing to do (no added information)
if (relation->relation != MONO_ANY_RELATION) {
int related_variable = relation->related_value.value.variable.variable;
MonoRelationsEvaluationContext *related_context = &(area->contexts [related_variable]);
MonoRelationsEvaluationStatus related_status = area->statuses [related_variable];
// The second condition in the "or" avoids messing with "back edges" in the graph traversal
// (they are simply ignored instead of triggering the handling of recursion)
if ( (related_status == MONO_RELATIONS_EVALUATION_NOT_STARTED) || !
((related_context->current_relation->related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) &&
(related_context->current_relation->related_value.value.variable.variable == variable))) {
// Evaluate the related variable
evaluate_relation_with_target_variable (area, related_variable, target_variable, context);
// Check if we are part of a recursive loop
if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
if (TRACE_ABC_REMOVAL) {
printf ("Recursivity detected for variable %d (target variable %d), status ", variable, target_variable);
print_evaluation_context_status (*status);
}
// If we are, check if the evaluation of the related variable is complete
if (related_status == MONO_RELATIONS_EVALUATION_COMPLETED) {
// If it is complete, we are part of a recursive definition.
// Since it is a *definition* (and definitions are evaluated *before*
// conditions because they are first in the list), intersection is not
// strictly necessary, we simply copy the ranges and apply the delta
context->ranges = related_context->ranges;
/* Delta has already been checked for over/under-flow when evaluating values */
MONO_ADD_DELTA_SAFELY_TO_RANGES (context->ranges, relation->related_value.value.variable.delta);
*status = MONO_RELATIONS_EVALUATION_COMPLETED;
if (TRACE_ABC_REMOVAL) {
printf (", ranges already computed, result: \n");
print_evaluation_context_ranges (&(context->ranges));
printf (" (delta is %d)\n", relation->related_value.value.variable.delta);
}
} else {
// If it is not complete, do nothing (we do not have enough information)
if (TRACE_ABC_REMOVAL) {
printf (", ranges not computed\n");
}
}
} else {
// If we are not (the common case) intersect the result
intersect_ranges( &(context->ranges), &(related_context->ranges), relation->related_value.value.variable.delta, relation->relation );
}
} else {
if (TRACE_ABC_REMOVAL) {
printf ("Relation is a back-edge in this traversal, skipping\n");
}
}
}
break;
case MONO_PHI_SUMMARIZED_VALUE: {
// We must compute all PHI alternatives, combining the results (with a union, which is a logical "or"),
// and intersect this result with the ranges in the context; we must also take into account recursions
// (with loops that can be ascending, descending, or indefinite)
MonoRelationsEvaluationRanges phi_ranges;
int phi;
gboolean is_ascending = FALSE;
gboolean is_descending = FALSE;
MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (phi_ranges);
for (phi = 0; phi < relation->related_value.value.phi.number_of_alternatives; phi++) {
int phi_alternative = relation->related_value.value.phi.phi_alternatives [phi];
evaluate_relation_with_target_variable (area, phi_alternative, target_variable, context);
// This means we are part of a recursive loop
if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
if (TRACE_ABC_REMOVAL) {
printf ("Recursivity detected for variable %d (target variable %d), status ", variable, target_variable);
print_evaluation_context_status (*status);
printf ("\n");
}
if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING) {
is_ascending = TRUE;
}
if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING) {
is_descending = TRUE;
}
if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE) {
is_ascending = TRUE;
is_descending = TRUE;
}
// Clear "recursivity" bits in the status (recursion has been handled)
*status = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
} else {
MONO_RELATIONS_EVALUATION_RANGES_UNION (phi_ranges, area->contexts [phi_alternative].ranges);
}
}
// Apply the effects of all recursive loops
if (is_ascending) {
phi_ranges.zero.upper = INT_MAX;
phi_ranges.variable.upper = INT_MAX;
}
if (is_descending) {
phi_ranges.zero.lower = INT_MIN;
phi_ranges.variable.lower = INT_MIN;
}
// Intersect final result
MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (context->ranges, phi_ranges);
break;
}
default:
g_assert_not_reached();
}
// Pass to next relation
relation = relation->next;
}
// Check if any recursivity bits are still in the status, and in any case clear them
if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
if (TRACE_ABC_REMOVAL) {
printf ("Recursivity for variable %d (target variable %d) discards computation, status ", variable, target_variable);
print_evaluation_context_status (*status);
printf ("\n");
}
// If yes, we did not have enough information (most likely we were evaluated inside a PHI, but we also
// depended on the same PHI, which was still in evaluation...), so clear the status to "NOT_STARTED"
// (if we will be evaluated again, the PHI will be already done, so our evaluation will succeed)
*status = MONO_RELATIONS_EVALUATION_NOT_STARTED;
} else {
if (TRACE_ABC_REMOVAL) {
printf ("Ranges for variable %d (target variable %d) computed: ", variable, target_variable);
print_evaluation_context_ranges (&(context->ranges));
printf ("\n");
}
// If not (the common case) the evaluation is complete, and the result is in the context
*status = MONO_RELATIONS_EVALUATION_COMPLETED;
}
break;
}
case MONO_RELATIONS_EVALUATION_IN_PROGRESS: {
// This means we are in a recursive loop
MonoRelationsEvaluationContext *current_context = father_context;
MonoRelationsEvaluationContext *last_context = context->father;
gboolean evaluation_can_be_recursive = TRUE;
gboolean evaluation_is_definition = TRUE;
int path_value = 0;
if (TRACE_ABC_REMOVAL) {
printf ("Evaluation of variable %d (target variable %d) already in progress\n", variable, target_variable);
print_evaluation_context (context, *status);
print_summarized_value_relation (context->current_relation);
printf ("\n");
}
// We must check if the loop can be a recursive definition (we scan the whole loop)
while (current_context != last_context) {
if (current_context == NULL) {
printf ("Broken recursive ring in ABC removal\n");
g_assert_not_reached ();
}
if (current_context->current_relation->relation_is_static_definition) {
if (current_context->current_relation->related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
/* No need to check path_value for over/under-flow, since delta should be safe */
path_value += current_context->current_relation->related_value.value.variable.delta;
} else if (current_context->current_relation->related_value.type != MONO_PHI_SUMMARIZED_VALUE) {
evaluation_can_be_recursive = FALSE;
}
} else {
evaluation_is_definition = FALSE;
evaluation_can_be_recursive = FALSE;
}
current_context = current_context->father;
}
// If this is a recursive definition, we properly flag the status in all the involved contexts
if (evaluation_is_definition) {
MonoRelationsEvaluationStatus recursive_status;
if (evaluation_can_be_recursive) {
if (path_value > 0) {
recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING;
} else if (path_value < 0) {
recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING;
} else {
recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE;
}
} else {
recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE;
}
if (TRACE_ABC_REMOVAL) {
printf ("Recursivity accepted (");
print_evaluation_context_status (recursive_status);
printf (")\n");
}
current_context = father_context;
while (current_context != last_context) {
int index = current_context - area->contexts;
MonoRelationsEvaluationStatus *current_status = &(area->statuses [index]);
*current_status = (MonoRelationsEvaluationStatus)(*current_status | recursive_status);
current_context = current_context->father;
}
} else {
if (TRACE_ABC_REMOVAL) {
printf ("Recursivity rejected (some relation in the cycle is not a defintion)\n");
}
}
break;
}
case MONO_RELATIONS_EVALUATION_COMPLETED: {
return;
}
default:
if (TRACE_ABC_REMOVAL) {
printf ("Variable %d (target variable %d) already in a recursive ring, skipping\n", variable, target_variable);
print_evaluation_context (context, *status);
print_summarized_value_relation (context->current_relation);
printf ("\n");
}
break;
}
}
/*
* Apply the given value kind to the given range
*/
static void
apply_value_kind_to_range (MonoRelationsEvaluationRange *range, MonoIntegerValueKind value_kind)
{
if (value_kind != MONO_UNKNOWN_INTEGER_VALUE) {
if (value_kind & MONO_UNSIGNED_VALUE_FLAG) {
if (range->lower < 0) {
range->lower = 0;
}
if ((value_kind & MONO_INTEGER_VALUE_SIZE_BITMASK) == 1) {
if (range->upper > 0xff) {
range->upper = 0xff;
}
} else if ((value_kind & MONO_INTEGER_VALUE_SIZE_BITMASK) == 2) {
if (range->upper > 0xffff) {
range->upper = 0xffff;
}
}
} else {
if ((value_kind & MONO_INTEGER_VALUE_SIZE_BITMASK) == 1) {
if (range->lower < -0x80) {
range->lower = -0x80;
}
if (range->upper > 0x7f) {
range->upper = 0x7f;
}
} else if ((value_kind & MONO_INTEGER_VALUE_SIZE_BITMASK) == 2) {
if (range->lower < -0x8000) {
range->lower = -0x8000;
}
if (range->upper > 0x7fff) {
range->upper = 0x7fff;
}
}
}
}
}
/*
* Attempt the removal of bounds checks from a MonoInst.
* inst: the MonoInst
* area: the current evaluation area (it contains the relation graph and
* memory for all the evaluation contexts is already allocated)
*/
static void
remove_abc_from_inst (MonoInst *ins, MonoVariableRelationsEvaluationArea *area)
{
/* FIXME: Add support for 'constant' arrays and constant indexes */
int array_variable = ins->sreg1;
int index_variable = ins->sreg2;
MonoRelationsEvaluationContext *array_context = &(area->contexts [array_variable]);
MonoRelationsEvaluationContext *index_context = &(area->contexts [index_variable]);
clean_contexts (area, area->cfg->next_vreg);
evaluate_relation_with_target_variable (area, index_variable, array_variable, NULL);
evaluate_relation_with_target_variable (area, array_variable, array_variable, NULL);
if ((index_context->ranges.zero.lower >=0) && ((index_context->ranges.variable.upper < 0)||(index_context->ranges.zero.upper < array_context->ranges.zero.lower))) {
if (REPORT_ABC_REMOVAL) {
printf ("ARRAY-ACCESS: removed bounds check on array %d with index %d\n",
array_variable, index_variable);
}
NULLIFY_INS (ins);
} else {
if (TRACE_ABC_REMOVAL) {
if (index_context->ranges.zero.lower >= 0) {
printf ("ARRAY-ACCESS: Removed lower bound check on array %d with index %d\n", array_variable, index_variable);
}
if (index_context->ranges.variable.upper < 0) {
printf ("ARRAY-ACCESS: Removed upper bound check (through variable) on array %d with index %d\n", array_variable, index_variable);
}
if (index_context->ranges.zero.upper < array_context->ranges.zero.lower) {
printf ("ARRAY-ACCESS: Removed upper bound check (through constant) on array %d with index %d\n", array_variable, index_variable);
}
}
}
}
static gboolean
eval_non_null (MonoVariableRelationsEvaluationArea *area, int reg)
{
MonoRelationsEvaluationContext *context = &(area->contexts [reg]);
clean_contexts (area, 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):
* - Get the BB entry condition
* - Add its relations to the relation graph in the evaluation area
* - Process all the MonoInst trees in the BB
* - Recursively process all the children BBs in the dominator tree
* - Remove the relations previously added to the relation graph
*
* bb: the BB that must be processed
* area: the current evaluation area (it contains the relation graph and
* memory for all the evaluation contexts is already allocated)
*/
static void
process_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoVariableRelationsEvaluationArea *area) {
int inst_index;
MonoInst *ins;
MonoAdditionalVariableRelationsForBB additional_relations;
GSList *dominated_bb, *l;
GSList *check_relations = NULL;
if (TRACE_ABC_REMOVAL) {
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) {
printf ("Adding relation 1 on variable %d: ", additional_relations.relation1.variable);
print_summarized_value_relation (&(additional_relations.relation1.relation));
printf ("\n");
}
if (additional_relations.relation2.relation.relation != MONO_ANY_RELATION) {
printf ("Adding relation 2 on variable %d: ", additional_relations.relation2.variable);
print_summarized_value_relation (&(additional_relations.relation2.relation));
printf ("\n");
}
}
apply_change_to_evaluation_area (area, &(additional_relations.relation1));
apply_change_to_evaluation_area (area, &(additional_relations.relation2));
inst_index = 0;
for (ins = bb->code; ins; ins = ins->next) {
MonoAdditionalVariableRelation *rel;
int array_var, index_var;
if (TRACE_ABC_REMOVAL) {
printf ("Processing instruction %d\n", inst_index);
inst_index++;
}
if (ins->opcode == OP_BOUNDS_CHECK) { /* Handle OP_LDELEMA2D, too */
if (TRACE_ABC_REMOVAL) {
printf ("Attempting check removal...\n");
}
array_var = ins->sreg1;
index_var = ins->sreg2;
remove_abc_from_inst (ins, area);
/* We can derive additional relations from the bounds check */
if (ins->opcode != OP_NOP) {
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;
rel->relation.related_value.value.variable.variable = array_var;
rel->relation.related_value.value.variable.delta = 0;
apply_change_to_evaluation_area (area, rel);
check_relations = g_slist_append_mempool (cfg->mempool, check_relations, rel);
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;
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);
}
}
if (ins->opcode == OP_CHECK_THIS) {
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)
add_non_null (area, cfg, ins->sreg1, &check_relations);
/*
* 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);
}
*/
}
}
if (TRACE_ABC_REMOVAL) {
printf ("Processing block %d [dfn %d] done.\n", bb->block_num, bb->dfn);
}
for (dominated_bb = bb->dominated; dominated_bb != NULL; dominated_bb = dominated_bb->next) {
process_block (cfg, (MonoBasicBlock*) (dominated_bb->data), area);
}
for (l = check_relations; l; l = l->next)
remove_change_from_evaluation_area ((MonoAdditionalVariableRelation *)l->data);
remove_change_from_evaluation_area (&(additional_relations.relation1));
remove_change_from_evaluation_area (&(additional_relations.relation2));
}
static MonoIntegerValueKind
type_to_value_kind (MonoType *type)
{
if (type->byref)
return MONO_UNKNOWN_INTEGER_VALUE;
switch (type->type) {
case MONO_TYPE_I1:
return MONO_INTEGER_VALUE_SIZE_1;
break;
case MONO_TYPE_U1:
return MONO_UNSIGNED_INTEGER_VALUE_SIZE_1;
break;
case MONO_TYPE_I2:
return MONO_INTEGER_VALUE_SIZE_2;
break;
case MONO_TYPE_U2:
return MONO_UNSIGNED_INTEGER_VALUE_SIZE_2;
break;
case MONO_TYPE_I4:
return MONO_INTEGER_VALUE_SIZE_4;
break;
case MONO_TYPE_U4:
return MONO_UNSIGNED_INTEGER_VALUE_SIZE_4;
break;
case MONO_TYPE_I:
return (MonoIntegerValueKind)SIZEOF_VOID_P;
break;
case MONO_TYPE_U:
return (MonoIntegerValueKind)(MONO_UNSIGNED_VALUE_FLAG | SIZEOF_VOID_P);
break;
case MONO_TYPE_I8:
return MONO_INTEGER_VALUE_SIZE_8;
break;
case MONO_TYPE_U8:
return MONO_UNSIGNED_INTEGER_VALUE_SIZE_8;
default:
return MONO_UNKNOWN_INTEGER_VALUE;
}
}
/**
* mono_perform_abc_removal:
* \param cfg Control Flow Graph
*
* Performs the ABC removal from a cfg in SSA form.
* It does the following:
* - Prepare the evaluation area
* - Allocate memory for the relation graph in the evaluation area
* (of course, only for variable definitions) and summarize there all
* variable definitions
* - Allocate memory for the evaluation contexts in the evaluation area
* - Recursively process all the BBs in the dominator tree (it is enough
* to invoke the processing on the entry BB)
*
* cfg: the method code
*/
void
mono_perform_abc_removal (MonoCompile *cfg)
{
MonoVariableRelationsEvaluationArea area;
MonoBasicBlock *bb;
int i;
verbose_level = cfg->verbose_level;
if (TRACE_ABC_REMOVAL) {
printf ("\nRemoving array bound checks in %s\n", mono_method_full_name (cfg->method, TRUE));
}
area.cfg = cfg;
area.relations = (MonoSummarizedValueRelation *)
mono_mempool_alloc (cfg->mempool, sizeof (MonoSummarizedValueRelation) * (cfg->next_vreg) * 2);
area.contexts = (MonoRelationsEvaluationContext *)
mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRelationsEvaluationContext) * (cfg->next_vreg));
area.statuses = (MonoRelationsEvaluationStatus *)
mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRelationsEvaluationStatus) * (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) {
MonoInst *ins;
if (TRACE_ABC_REMOVAL)
printf ("\nABCREM BLOCK %d:\n", bb->block_num);
for (ins = bb->code; ins; ins = ins->next) {
const char *spec = INS_INFO (ins->opcode);
gint32 idx, *reg;
if (spec [MONO_INST_DEST] == ' ' || MONO_IS_STORE_MEMBASE (ins))
continue;
MONO_INS_FOR_EACH_REG (ins, idx, reg) {
MonoInst *var = get_vreg_to_inst (cfg, *reg);
if (var && (!MONO_VARINFO (cfg, var->inst_c0)->def))
break;
}
if (idx < MONO_INST_LEN) {
if (TRACE_ABC_REMOVAL)
printf ("Global register %d is not in the SSA form, skipping.\n", *reg);
continue;
}
if (spec [MONO_INST_DEST] == 'i') {
MonoIntegerValueKind effective_value_kind;
MonoRelationsEvaluationRange range;
MonoSummarizedValueRelation *type_relation;
MonoInst *var;
if (TRACE_ABC_REMOVAL)
mono_print_ins (ins);
var = get_vreg_to_inst (cfg, ins->dreg);
if (var)
area.variable_value_kind [ins->dreg] = type_to_value_kind (var->inst_vtype);
effective_value_kind = get_relation_from_ins (&area, ins, &area.relations [ins->dreg], area.variable_value_kind [ins->dreg]);
MONO_MAKE_RELATIONS_EVALUATION_RANGE_WEAK (range);
apply_value_kind_to_range (&range, area.variable_value_kind [ins->dreg]);
apply_value_kind_to_range (&range, effective_value_kind);
if (range.upper < INT_MAX) {
type_relation = (MonoSummarizedValueRelation *) mono_mempool_alloc (cfg->mempool, sizeof (MonoSummarizedValueRelation));
type_relation->relation = MONO_LE_RELATION;
type_relation->related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
type_relation->related_value.value.constant.value = range.upper;
type_relation->relation_is_static_definition = TRUE;
type_relation->next = area.relations [ins->dreg].next;
area.relations [ins->dreg].next = type_relation;
if (TRACE_ABC_REMOVAL) {
printf ("[var%d <= %d]", ins->dreg, range.upper);
}
}
if (range.lower > INT_MIN) {
type_relation = (MonoSummarizedValueRelation *) mono_mempool_alloc (cfg->mempool, sizeof (MonoSummarizedValueRelation));
type_relation->relation = MONO_GE_RELATION;
type_relation->related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
type_relation->related_value.value.constant.value = range.lower;
type_relation->relation_is_static_definition = TRUE;
type_relation->next = area.relations [ins->dreg].next;
area.relations [ins->dreg].next = type_relation;
if (TRACE_ABC_REMOVAL) {
printf ("[var%d >= %d]", ins->dreg, range.lower);
}
}
if (TRACE_ABC_REMOVAL) {
printf ("Summarized variable %d: ", ins->dreg);
print_summarized_value (&(area.relations [ins->dreg].related_value));
printf ("\n");
}
}
}
}
/* Add symmetric relations */
for (i = 0; i < cfg->next_vreg; i++) {
if (area.relations [i].related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
int related_index = cfg->next_vreg + i;
int related_variable = area.relations [i].related_value.value.variable.variable;
area.relations [related_index].relation = MONO_EQ_RELATION;
area.relations [related_index].relation_is_static_definition = TRUE;
area.relations [related_index].related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
area.relations [related_index].related_value.value.variable.variable = i;
area.relations [related_index].related_value.value.variable.delta = - area.relations [i].related_value.value.variable.delta;
area.relations [related_index].next = area.relations [related_variable].next;
area.relations [related_variable].next = &(area.relations [related_index]);
if (TRACE_ABC_REMOVAL) {
printf ("Added symmetric summarized value for variable variable %d (to %d): ", i, related_variable);
print_summarized_value (&(area.relations [related_index].related_value));
printf ("\n");
}
}
}
process_block (cfg, cfg->bblocks [0], &area);
}
#else /* !DISABLE_JIT */
MONO_EMPTY_SOURCE_FILE (abcremoval);
#endif /* !DISABLE_JIT */