3 * Array bounds check removal
6 * Massimiliano Mantione (massi@ximian.com)
8 * (C) 2004 Ximian, Inc. http://www.ximian.com
13 #include <mono/metadata/debug-helpers.h>
14 #include <mono/metadata/mempool.h>
15 #include <mono/metadata/opcodes.h>
16 #include <mono/metadata/mempool-internals.h>
17 #include <mono/utils/mono-compiler.h>
23 #include "abcremoval.h"
25 #if SIZEOF_VOID_P == 8
26 #define OP_PCONST OP_I8CONST
28 #define OP_PCONST OP_ICONST
32 #define TRACE_ABC_REMOVAL (verbose_level > 2)
33 #define REPORT_ABC_REMOVAL (verbose_level > 1)
36 * A little hack for the verbosity level.
37 * The verbosity level is stored in the cfg, but not all functions that must
38 * print something see the cfg, so we store the verbosity level here at the
39 * beginning of the algorithm.
40 * This is not thread safe (does not handle correctly different verbosity
41 * levels in different threads), and is not exact in case of dynamic changes
42 * of the verbosity level...
43 * Anyway, this is not needed, all that can happen is that something more
44 * (or less) is logged, the result is in any case correct.
46 static int verbose_level;
49 #define RELATION_BETWEEN_VALUES(value,related_value) (\
50 ((value) > (related_value))? MONO_GT_RELATION :\
51 (((value) < (related_value))? MONO_LT_RELATION : MONO_EQ_RELATION))
53 #define MAKE_VALUE_ANY(v) do{\
54 (v).type = MONO_ANY_SUMMARIZED_VALUE;\
57 #define MAKE_VALUE_RELATION_ANY(r) do{\
58 (r)->relation = MONO_ANY_RELATION;\
59 MAKE_VALUE_ANY((r)->related_value);\
62 #define INITIALIZE_VALUE_RELATION(r) do{\
63 MAKE_VALUE_RELATION_ANY((r));\
67 #define MONO_NEGATED_RELATION(r) ((MonoValueRelation)((~(r))&MONO_ANY_RELATION))
68 #define MONO_SYMMETRIC_RELATION(r) ((MonoValueRelation)(((r)&MONO_EQ_RELATION)|(((r)&MONO_LT_RELATION)<<1)|((r&MONO_GT_RELATION)>>1)))
73 print_relation (int relation) {
76 if (relation & MONO_LT_RELATION) {
80 if (relation & MONO_EQ_RELATION) {
87 if (relation & MONO_GT_RELATION) {
98 print_summarized_value (MonoSummarizedValue *value) {
99 switch (value->type) {
100 case MONO_ANY_SUMMARIZED_VALUE:
103 case MONO_CONSTANT_SUMMARIZED_VALUE:
104 printf ("CONSTANT %d", value->value.constant.value);
106 case MONO_VARIABLE_SUMMARIZED_VALUE:
107 printf ("VARIABLE %d, delta %d", value->value.variable.variable, value->value.variable.delta);
109 case MONO_PHI_SUMMARIZED_VALUE: {
112 for (phi = 0; phi < value->value.phi.number_of_alternatives; phi++) {
113 if (phi) printf (",");
114 printf ("%d", value->value.phi.phi_alternatives [phi]);
120 g_assert_not_reached ();
125 print_summarized_value_relation (MonoSummarizedValueRelation *relation) {
126 printf ("Relation ");
127 print_relation (relation->relation);
128 printf (" with value ");
129 print_summarized_value (&(relation->related_value));
134 print_summarized_value_relation_chain (MonoSummarizedValueRelation *relation) {
135 printf ("Relations:\n");
137 print_summarized_value_relation (relation);
139 relation = relation->next;
145 print_evaluation_context_status (MonoRelationsEvaluationStatus status) {
146 if (status == MONO_RELATIONS_EVALUATION_NOT_STARTED) {
147 printf ("EVALUATION_NOT_STARTED");
149 gboolean print_or = FALSE;
152 if (status & MONO_RELATIONS_EVALUATION_IN_PROGRESS) {
153 if (print_or) printf ("|");
154 printf ("EVALUATION_IN_PROGRESS");
157 if (status & MONO_RELATIONS_EVALUATION_COMPLETED) {
158 if (print_or) printf ("|");
159 printf ("EVALUATION_COMPLETED");
162 if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING) {
163 if (print_or) printf ("|");
164 printf ("RECURSIVELY_ASCENDING");
167 if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING) {
168 if (print_or) printf ("|");
169 printf ("RECURSIVELY_DESCENDING");
172 if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE) {
173 if (print_or) printf ("|");
174 printf ("RECURSIVELY_INDEFINITE");
183 print_evaluation_context_ranges (MonoRelationsEvaluationRanges *ranges) {
184 printf ("(ranges: zero [%d,%d], variable [%d,%d])", ranges->zero.lower, ranges->zero.upper, ranges->variable.lower, ranges->variable.upper);
188 print_evaluation_context (MonoRelationsEvaluationContext *context, MonoRelationsEvaluationStatus status) {
189 print_evaluation_context_status (status);
190 if (status & (MONO_RELATIONS_EVALUATION_IN_PROGRESS|MONO_RELATIONS_EVALUATION_COMPLETED)) {
191 print_evaluation_context_ranges (&(context->ranges));
198 print_evaluation_area (MonoVariableRelationsEvaluationArea *area) {
200 printf ("Dump of evaluation area (%d variables):\n", area->cfg->num_varinfo);
201 for (i = 0; i < area->cfg->num_varinfo; i++) {
202 printf ("Variable %d: ", i);
203 print_evaluation_context (&(area->contexts [i]));
204 print_summarized_value_relation_chain (&(area->relations [i]));
209 print_evaluation_area_contexts (MonoVariableRelationsEvaluationArea *area) {
211 printf ("Dump of evaluation area contexts (%d variables):\n", area->cfg->num_varinfo);
212 for (i = 0; i < area->cfg->num_varinfo; i++) {
213 printf ("Variable %d: ", i);
214 print_evaluation_context (&(area->contexts [i]));
220 * Check if the delta of an integer variable value is safe with respect
221 * to the variable size in bytes and its kind (signed or unsigned).
222 * If the delta is not safe, make the value an "any".
224 static G_GNUC_UNUSED void
225 check_delta_safety (MonoVariableRelationsEvaluationArea *area, MonoSummarizedValue *value) {
226 if (value->type == MONO_VARIABLE_SUMMARIZED_VALUE) {
227 int variable = value->value.variable.variable;
228 int delta = value->value.variable.delta;
229 if ((area->variable_value_kind [variable]) & MONO_UNSIGNED_VALUE_FLAG) {
231 MAKE_VALUE_ANY (*value);
234 if (((area->variable_value_kind [variable]) & MONO_INTEGER_VALUE_SIZE_BITMASK) < 4) {
235 MAKE_VALUE_ANY (*value);
236 } else if (delta > 16) {
237 MAKE_VALUE_ANY (*value);
244 * get_relation_from_ins:
246 * Obtain relations from a MonoInst.
248 * result_value_kind: the "expected" kind of result;
249 * result: the "summarized" value
250 * returns the "actual" kind of result, if guessable (otherwise MONO_UNKNOWN_INTEGER_VALUE)
252 static MonoIntegerValueKind
253 get_relation_from_ins (MonoVariableRelationsEvaluationArea *area, MonoInst *ins, MonoSummarizedValueRelation *result, MonoIntegerValueKind result_value_kind)
255 MonoIntegerValueKind value_kind;
256 MonoSummarizedValue *value = &result->related_value;
258 if (ins->type == STACK_I8) {
259 value_kind = MONO_INTEGER_VALUE_SIZE_8;
260 } else if (ins->type == STACK_I4) {
261 value_kind = MONO_INTEGER_VALUE_SIZE_4;
263 value_kind = MONO_UNKNOWN_INTEGER_VALUE;
266 result->relation = MONO_EQ_RELATION;
267 MAKE_VALUE_ANY (*value);
269 switch (ins->opcode) {
271 value->type = MONO_CONSTANT_SUMMARIZED_VALUE;
272 value->value.constant.value = ins->inst_c0;
275 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
276 value->value.variable.variable = ins->sreg1;
277 value->value.variable.delta = 0;
280 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
281 value->value.variable.variable = ins->sreg1;
282 value->value.variable.delta = 0;
283 value_kind = MONO_INTEGER_VALUE_SIZE_8;
286 value->type = MONO_PHI_SUMMARIZED_VALUE;
287 value->value.phi.number_of_alternatives = *(ins->inst_phi_args);
288 value->value.phi.phi_alternatives = ins->inst_phi_args + 1;
291 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
292 value->value.variable.variable = ins->sreg1;
293 value->value.variable.delta = ins->inst_imm;
295 //check_delta_safety (area, result);
298 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
299 value->value.variable.variable = ins->sreg1;
300 value->value.variable.delta = -ins->inst_imm;
302 //check_delta_safety (area, result);
305 /* The result of an unsigned remainder is 0 < x < the divisor */
306 result->relation = MONO_LT_RELATION;
307 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
308 value->value.variable.variable = ins->sreg2;
309 value->value.variable.delta = 0;
310 value_kind = MONO_UNSIGNED_INTEGER_VALUE_SIZE_4;
314 * We represent arrays by their length, so r1<-ldlen r2 is stored
315 * as r1 == r2 in the evaluation graph.
317 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
318 value->value.variable.variable = ins->sreg1;
319 value->value.variable.delta = 0;
320 value_kind = MONO_UNSIGNED_INTEGER_VALUE_SIZE_4;
323 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
324 value->value.variable.variable = ins->sreg1;
325 value->value.variable.delta = 0;
326 area->defs [ins->dreg] = ins;
329 /* The result is non-null */
330 result->relation = MONO_GT_RELATION;
331 value->type = MONO_CONSTANT_SUMMARIZED_VALUE;
332 value->value.constant.value = 0;
335 /* FIXME: Add more opcodes */
337 /* These opcodes are not currently handled while running SciMark, first
338 * column is the number of times the warning was shown:
370 * 12 outarg_vtretaddr
398 static MonoValueRelation
399 get_relation_from_branch_instruction (MonoInst *ins)
401 if (MONO_IS_COND_BRANCH_OP (ins)) {
402 CompRelation rel = mono_opcode_to_cond (ins->opcode);
406 return MONO_EQ_RELATION;
408 return MONO_NE_RELATION;
411 return MONO_LE_RELATION;
414 return MONO_GE_RELATION;
417 return MONO_LT_RELATION;
420 return MONO_GT_RELATION;
422 g_assert_not_reached ();
423 return MONO_ANY_RELATION;
426 return MONO_ANY_RELATION;
431 * Given a BB, find its entry condition and put its relations in a
432 * "MonoAdditionalVariableRelationsForBB" structure.
434 * relations: the resulting relations (entry condition of the given BB)
437 get_relations_from_previous_bb (MonoVariableRelationsEvaluationArea *area, MonoBasicBlock *bb, MonoAdditionalVariableRelationsForBB *relations)
439 MonoBasicBlock *in_bb;
440 MonoInst *ins, *compare, *branch;
441 MonoValueRelation branch_relation;
442 MonoValueRelation symmetric_relation;
445 INITIALIZE_VALUE_RELATION (&(relations->relation1.relation));
446 relations->relation1.relation.relation_is_static_definition = FALSE;
447 relations->relation1.relation.next = NULL;
448 relations->relation1.insertion_point = NULL;
449 relations->relation1.variable = -1;
450 INITIALIZE_VALUE_RELATION (&(relations->relation2.relation));
451 relations->relation2.relation.relation_is_static_definition = FALSE;
452 relations->relation2.relation.next = NULL;
453 relations->relation2.insertion_point = NULL;
454 relations->relation2.variable = -1;
456 if (bb->in_count == 1) { /* Should write the code to "sum" conditions... */
457 in_bb = bb->in_bb [0];
459 if ((in_bb->last_ins == NULL) || (in_bb->code == in_bb->last_ins))
462 for (ins = in_bb->code; ins->next != in_bb->last_ins; ins = ins->next)
467 branch_relation = get_relation_from_branch_instruction (branch);
469 if (branch_relation != MONO_ANY_RELATION) {
470 if (branch->inst_true_bb == bb) {
472 } else if (branch->inst_false_bb == bb) {
476 g_assert_not_reached ();
479 branch_relation = MONO_NEGATED_RELATION (branch_relation);
480 symmetric_relation = MONO_SYMMETRIC_RELATION (branch_relation);
482 /* FIXME: Other compare opcodes */
483 if (compare->opcode == OP_ICOMPARE) {
484 relations->relation1.variable = compare->sreg1;
485 relations->relation1.relation.relation = branch_relation;
486 relations->relation1.relation.related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
487 relations->relation1.relation.related_value.value.variable.variable = compare->sreg2;
488 relations->relation1.relation.related_value.value.variable.delta = 0;
490 relations->relation2.variable = compare->sreg2;
491 relations->relation2.relation.relation = symmetric_relation;
492 relations->relation2.relation.related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
493 relations->relation2.relation.related_value.value.variable.variable = compare->sreg1;
494 relations->relation2.relation.related_value.value.variable.delta = 0;
495 } else if (compare->opcode == OP_ICOMPARE_IMM) {
496 relations->relation1.variable = compare->sreg1;
497 relations->relation1.relation.relation = branch_relation;
498 relations->relation1.relation.related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
499 relations->relation1.relation.related_value.value.constant.value = compare->inst_imm;
506 * Add the given relations to the evaluation area.
507 * area: the evaluation area
508 * change: the relations that must be added
511 apply_change_to_evaluation_area (MonoVariableRelationsEvaluationArea *area, MonoAdditionalVariableRelation *change)
513 MonoSummarizedValueRelation *base_relation;
515 if (change->relation.relation != MONO_ANY_RELATION) {
516 base_relation = &(area->relations [change->variable]);
517 while ((base_relation->next != NULL) && (base_relation->next->relation_is_static_definition)) {
518 base_relation = base_relation->next;
520 change->insertion_point = base_relation;
521 change->relation.next = base_relation->next;
522 base_relation->next = &(change->relation);
527 * Remove the given relation from the evaluation area.
528 * change: the relation that must be removed
531 remove_change_from_evaluation_area (MonoAdditionalVariableRelation *change)
533 if (change->insertion_point != NULL) {
534 change->insertion_point->next = change->relation.next;
535 change->relation.next = NULL;
541 clean_contexts (MonoVariableRelationsEvaluationArea *area, int number)
543 memset(area->statuses, MONO_RELATIONS_EVALUATION_NOT_STARTED, number * sizeof(MonoRelationsEvaluationStatus));
548 * Perform the intersection of a range and a constant value (taking into
549 * account the relation that the value has with the range).
550 * range: the range that will be intersected with the value
551 * value: the value that will be intersected with the range
552 * relation: the relation between the range and the value
555 intersect_value( MonoRelationsEvaluationRange *range, int value, MonoValueRelation relation )
558 case MONO_NO_RELATION:
559 MONO_MAKE_RELATIONS_EVALUATION_RANGE_IMPOSSIBLE (*range);
561 case MONO_ANY_RELATION:
563 case MONO_EQ_RELATION:
564 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, value);
565 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, value);
567 case MONO_NE_RELATION: {
568 /* IMPROVEMENT Figure this out! (ignoring it is safe anyway) */
571 case MONO_LT_RELATION:
572 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (value));
574 case MONO_LE_RELATION:
575 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, value);
577 case MONO_GT_RELATION:
578 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (value));
580 case MONO_GE_RELATION:
581 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, value);
584 g_assert_not_reached();
590 * Perform the intersection of two pairs of ranges (taking into account the
591 * relation between the ranges and a given delta).
592 * ranges: the ranges that will be intersected
593 * other_ranges the other ranges that will be intersected
594 * delta: the delta between the pairs of ranges
595 * relation: the relation between the pairs of ranges
598 intersect_ranges( MonoRelationsEvaluationRanges *ranges, MonoRelationsEvaluationRanges *other_ranges, int delta, MonoValueRelation relation )
602 case MONO_NO_RELATION:
603 MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (*ranges);
605 case MONO_ANY_RELATION:
607 case MONO_EQ_RELATION:
608 MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (*ranges, *other_ranges);
610 case MONO_NE_RELATION: {
611 /* FIXME Figure this out! (ignoring it is safe anyway) */
614 case MONO_LT_RELATION:
615 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->zero.upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->zero.upper));
616 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->variable.upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->variable.upper));
618 case MONO_LE_RELATION:
619 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->zero.upper, other_ranges->zero.upper);
620 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->variable.upper, other_ranges->variable.upper);
622 case MONO_GT_RELATION:
623 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->zero.lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->zero.lower));
624 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->variable.lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->variable.lower));
626 case MONO_GE_RELATION:
627 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->zero.lower, other_ranges->zero.lower);
628 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->variable.lower, other_ranges->variable.lower);
631 g_assert_not_reached();
634 MonoRelationsEvaluationRanges translated_ranges = *other_ranges;
635 MONO_ADD_DELTA_SAFELY_TO_RANGES (translated_ranges, delta);
636 intersect_ranges( ranges, &translated_ranges, FALSE, relation );
641 * Recursive method that traverses the relation graph to evaluate the
642 * relation between two variables.
643 * At the end of the execution, the resulting ranges are in the context of
644 * the "starting" variable.
645 * area: the current evaluation area (it contains the relation graph and
646 * memory for all the evaluation contexts is already allocated)
647 * variable: starting variable (the value ranges in its context are the result
648 * of the execution of this procedure)
649 * target_variable: the variable with respect to which the starting variable
650 * is evaluated (tipically the starting variable is the index
651 * and the target one is the array (which means its length))
652 * father_context: the previous evaluation context in recursive invocations
653 * (or NULL for the first invocation)
656 evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *area, const int variable, const int target_variable, MonoRelationsEvaluationContext *father_context)
658 MonoRelationsEvaluationContext * const context = &(area->contexts [variable]);
659 MonoRelationsEvaluationStatus * const status = &(area->statuses [variable]);
661 // First of all, we check the evaluation status
662 // (what must be done is *very* different in each case)
664 case MONO_RELATIONS_EVALUATION_NOT_STARTED: {
665 MonoSummarizedValueRelation *relation = &(area->relations [variable]);
667 if (TRACE_ABC_REMOVAL) {
668 printf ("Evaluating variable %d (target variable %d)\n", variable, target_variable);
669 print_summarized_value_relation (relation);
673 // We properly inizialize the context
674 *status = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
675 context->father = father_context;
676 MONO_MAKE_RELATIONS_EVALUATION_RANGES_WEAK (context->ranges);
678 // If we have found the target variable, we can set the range
679 // related to it in the context to "equal" (which is [0,0])
680 if (variable == target_variable) {
681 if (TRACE_ABC_REMOVAL) {
682 printf ("Target variable reached (%d), continuing to evaluate relations with constants\n", variable);
684 context->ranges.variable.lower = 0;
685 context->ranges.variable.upper = 0;
688 // Examine all relations for this variable (scan the list)
689 // The contribute of each relation will be intersected (logical and)
690 while (relation != NULL) {
691 context->current_relation = relation;
693 if (TRACE_ABC_REMOVAL) {
694 printf ("Processing (%d): ", variable);
695 print_summarized_value_relation (relation);
699 // We decie what to do according the the type of the related value
700 switch (relation->related_value.type) {
701 case MONO_ANY_SUMMARIZED_VALUE:
702 // No added information, skip it
704 case MONO_CONSTANT_SUMMARIZED_VALUE:
705 // Intersect range with constant (taking into account the relation)
706 intersect_value (&(context->ranges.zero), relation->related_value.value.constant.value, relation->relation);
708 case MONO_VARIABLE_SUMMARIZED_VALUE:
709 // Generally, evaluate related variable and intersect ranges.
710 // However, some check is necessary...
712 // If the relation is "ANY", nothing to do (no added information)
713 if (relation->relation != MONO_ANY_RELATION) {
714 int related_variable = relation->related_value.value.variable.variable;
715 MonoRelationsEvaluationContext *related_context = &(area->contexts [related_variable]);
716 MonoRelationsEvaluationStatus related_status = area->statuses [related_variable];
718 // The second condition in the "or" avoids messing with "back edges" in the graph traversal
719 // (they are simply ignored instead of triggering the handling of recursion)
720 if ( (related_status == MONO_RELATIONS_EVALUATION_NOT_STARTED) || !
721 ((related_context->current_relation->related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) &&
722 (related_context->current_relation->related_value.value.variable.variable == variable))) {
723 // Evaluate the related variable
724 evaluate_relation_with_target_variable (area, related_variable, target_variable, context);
726 // Check if we are part of a recursive loop
727 if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
728 if (TRACE_ABC_REMOVAL) {
729 printf ("Recursivity detected for variable %d (target variable %d), status ", variable, target_variable);
730 print_evaluation_context_status (*status);
733 // If we are, check if the evaluation of the related variable is complete
734 if (related_status == MONO_RELATIONS_EVALUATION_COMPLETED) {
735 // If it is complete, we are part of a recursive definition.
736 // Since it is a *definition* (and definitions are evaluated *before*
737 // conditions because they are first in the list), intersection is not
738 // strictly necessary, we simply copy the ranges and apply the delta
739 context->ranges = related_context->ranges;
740 /* Delta has already been checked for over/under-flow when evaluating values */
741 MONO_ADD_DELTA_SAFELY_TO_RANGES (context->ranges, relation->related_value.value.variable.delta);
742 *status = MONO_RELATIONS_EVALUATION_COMPLETED;
743 if (TRACE_ABC_REMOVAL) {
744 printf (", ranges already computed, result: \n");
745 print_evaluation_context_ranges (&(context->ranges));
746 printf (" (delta is %d)\n", relation->related_value.value.variable.delta);
749 // If it is not complete, do nothing (we do not have enough information)
750 if (TRACE_ABC_REMOVAL) {
751 printf (", ranges not computed\n");
755 // If we are not (the common case) intersect the result
756 intersect_ranges( &(context->ranges), &(related_context->ranges), relation->related_value.value.variable.delta, relation->relation );
759 if (TRACE_ABC_REMOVAL) {
760 printf ("Relation is a back-edge in this traversal, skipping\n");
765 case MONO_PHI_SUMMARIZED_VALUE: {
766 // We must compute all PHI alternatives, combining the results (with a union, which is a logical "or"),
767 // and intersect this result with the ranges in the context; we must also take into account recursions
768 // (with loops that can be ascending, descending, or indefinite)
769 MonoRelationsEvaluationRanges phi_ranges;
771 gboolean is_ascending = FALSE;
772 gboolean is_descending = FALSE;
774 MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (phi_ranges);
775 for (phi = 0; phi < relation->related_value.value.phi.number_of_alternatives; phi++) {
776 int phi_alternative = relation->related_value.value.phi.phi_alternatives [phi];
777 evaluate_relation_with_target_variable (area, phi_alternative, target_variable, context);
779 // This means we are part of a recursive loop
780 if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
781 if (TRACE_ABC_REMOVAL) {
782 printf ("Recursivity detected for variable %d (target variable %d), status ", variable, target_variable);
783 print_evaluation_context_status (*status);
786 if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING) {
789 if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING) {
790 is_descending = TRUE;
792 if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE) {
794 is_descending = TRUE;
797 // Clear "recursivity" bits in the status (recursion has been handled)
798 *status = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
800 MONO_RELATIONS_EVALUATION_RANGES_UNION (phi_ranges, area->contexts [phi_alternative].ranges);
804 // Apply the effects of all recursive loops
806 phi_ranges.zero.upper = INT_MAX;
807 phi_ranges.variable.upper = INT_MAX;
810 phi_ranges.zero.lower = INT_MIN;
811 phi_ranges.variable.lower = INT_MIN;
814 // Intersect final result
815 MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (context->ranges, phi_ranges);
819 g_assert_not_reached();
822 // Pass to next relation
823 relation = relation->next;
826 // Check if any recursivity bits are still in the status, and in any case clear them
827 if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
828 if (TRACE_ABC_REMOVAL) {
829 printf ("Recursivity for variable %d (target variable %d) discards computation, status ", variable, target_variable);
830 print_evaluation_context_status (*status);
833 // If yes, we did not have enough information (most likely we were evaluated inside a PHI, but we also
834 // depended on the same PHI, which was still in evaluation...), so clear the status to "NOT_STARTED"
835 // (if we will be evaluated again, the PHI will be already done, so our evaluation will succeed)
836 *status = MONO_RELATIONS_EVALUATION_NOT_STARTED;
838 if (TRACE_ABC_REMOVAL) {
839 printf ("Ranges for variable %d (target variable %d) computed: ", variable, target_variable);
840 print_evaluation_context_ranges (&(context->ranges));
843 // If not (the common case) the evaluation is complete, and the result is in the context
844 *status = MONO_RELATIONS_EVALUATION_COMPLETED;
848 case MONO_RELATIONS_EVALUATION_IN_PROGRESS: {
849 // This means we are in a recursive loop
850 MonoRelationsEvaluationContext *current_context = father_context;
851 MonoRelationsEvaluationContext *last_context = context->father;
852 gboolean evaluation_can_be_recursive = TRUE;
853 gboolean evaluation_is_definition = TRUE;
856 if (TRACE_ABC_REMOVAL) {
857 printf ("Evaluation of variable %d (target variable %d) already in progress\n", variable, target_variable);
858 print_evaluation_context (context, *status);
859 print_summarized_value_relation (context->current_relation);
863 // We must check if the loop can be a recursive definition (we scan the whole loop)
864 while (current_context != last_context) {
865 if (current_context == NULL) {
866 printf ("Broken recursive ring in ABC removal\n");
867 g_assert_not_reached ();
870 if (current_context->current_relation->relation_is_static_definition) {
871 if (current_context->current_relation->related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
872 /* No need to check path_value for over/under-flow, since delta should be safe */
873 path_value += current_context->current_relation->related_value.value.variable.delta;
874 } else if (current_context->current_relation->related_value.type != MONO_PHI_SUMMARIZED_VALUE) {
875 evaluation_can_be_recursive = FALSE;
878 evaluation_is_definition = FALSE;
879 evaluation_can_be_recursive = FALSE;
882 current_context = current_context->father;
885 // If this is a recursive definition, we properly flag the status in all the involved contexts
886 if (evaluation_is_definition) {
887 MonoRelationsEvaluationStatus recursive_status;
888 if (evaluation_can_be_recursive) {
889 if (path_value > 0) {
890 recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING;
891 } else if (path_value < 0) {
892 recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING;
894 recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE;
897 recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE;
900 if (TRACE_ABC_REMOVAL) {
901 printf ("Recursivity accepted (");
902 print_evaluation_context_status (recursive_status);
906 current_context = father_context;
907 while (current_context != last_context) {
908 int index = current_context - area->contexts;
909 MonoRelationsEvaluationStatus *current_status = &(area->statuses [index]);
910 *current_status = (MonoRelationsEvaluationStatus)(*current_status | recursive_status);
911 current_context = current_context->father;
914 if (TRACE_ABC_REMOVAL) {
915 printf ("Recursivity rejected (some relation in the cycle is not a defintion)\n");
920 case MONO_RELATIONS_EVALUATION_COMPLETED: {
924 if (TRACE_ABC_REMOVAL) {
925 printf ("Variable %d (target variable %d) already in a recursive ring, skipping\n", variable, target_variable);
926 print_evaluation_context (context, *status);
927 print_summarized_value_relation (context->current_relation);
936 * Apply the given value kind to the given range
939 apply_value_kind_to_range (MonoRelationsEvaluationRange *range, MonoIntegerValueKind value_kind)
941 if (value_kind != MONO_UNKNOWN_INTEGER_VALUE) {
942 if (value_kind & MONO_UNSIGNED_VALUE_FLAG) {
943 if (range->lower < 0) {
946 if ((value_kind & MONO_INTEGER_VALUE_SIZE_BITMASK) == 1) {
947 if (range->upper > 0xff) {
950 } else if ((value_kind & MONO_INTEGER_VALUE_SIZE_BITMASK) == 2) {
951 if (range->upper > 0xffff) {
952 range->upper = 0xffff;
956 if ((value_kind & MONO_INTEGER_VALUE_SIZE_BITMASK) == 1) {
957 if (range->lower < -0x80) {
958 range->lower = -0x80;
960 if (range->upper > 0x7f) {
963 } else if ((value_kind & MONO_INTEGER_VALUE_SIZE_BITMASK) == 2) {
964 if (range->lower < -0x8000) {
965 range->lower = -0x8000;
967 if (range->upper > 0x7fff) {
968 range->upper = 0x7fff;
976 * Attempt the removal of bounds checks from a MonoInst.
978 * area: the current evaluation area (it contains the relation graph and
979 * memory for all the evaluation contexts is already allocated)
982 remove_abc_from_inst (MonoInst *ins, MonoVariableRelationsEvaluationArea *area)
984 /* FIXME: Add support for 'constant' arrays and constant indexes */
986 int array_variable = ins->sreg1;
987 int index_variable = ins->sreg2;
988 MonoRelationsEvaluationContext *array_context = &(area->contexts [array_variable]);
989 MonoRelationsEvaluationContext *index_context = &(area->contexts [index_variable]);
991 clean_contexts (area, area->cfg->next_vreg);
993 evaluate_relation_with_target_variable (area, index_variable, array_variable, NULL);
994 evaluate_relation_with_target_variable (area, array_variable, array_variable, NULL);
996 if ((index_context->ranges.zero.lower >=0) && ((index_context->ranges.variable.upper < 0)||(index_context->ranges.zero.upper < array_context->ranges.zero.lower))) {
997 if (REPORT_ABC_REMOVAL) {
998 printf ("ARRAY-ACCESS: removed bounds check on array %d with index %d\n",
999 array_variable, index_variable);
1003 if (TRACE_ABC_REMOVAL) {
1004 if (index_context->ranges.zero.lower >= 0) {
1005 printf ("ARRAY-ACCESS: Removed lower bound check on array %d with index %d\n", array_variable, index_variable);
1007 if (index_context->ranges.variable.upper < 0) {
1008 printf ("ARRAY-ACCESS: Removed upper bound check (through variable) on array %d with index %d\n", array_variable, index_variable);
1010 if (index_context->ranges.zero.upper < array_context->ranges.zero.lower) {
1011 printf ("ARRAY-ACCESS: Removed upper bound check (through constant) on array %d with index %d\n", array_variable, index_variable);
1018 eval_non_null (MonoVariableRelationsEvaluationArea *area, int reg)
1020 MonoRelationsEvaluationContext *context = &(area->contexts [reg]);
1022 clean_contexts (area, area->cfg->next_vreg);
1023 evaluate_relation_with_target_variable (area, reg, reg, NULL);
1025 return context->ranges.zero.lower > 0;
1029 add_non_null (MonoVariableRelationsEvaluationArea *area, MonoCompile *cfg, int reg,
1030 GSList **check_relations)
1032 MonoAdditionalVariableRelation *rel;
1034 rel = (MonoAdditionalVariableRelation *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoAdditionalVariableRelation));
1035 rel->variable = reg;
1036 rel->relation.relation = MONO_GT_RELATION;
1037 rel->relation.related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
1038 rel->relation.related_value.value.constant.value = 0;
1040 apply_change_to_evaluation_area (area, rel);
1042 *check_relations = g_slist_append_mempool (cfg->mempool, *check_relations, rel);
1046 * Process a BB removing bounds checks from array accesses.
1047 * It does the following (in sequence):
1048 * - Get the BB entry condition
1049 * - Add its relations to the relation graph in the evaluation area
1050 * - Process all the MonoInst trees in the BB
1051 * - Recursively process all the children BBs in the dominator tree
1052 * - Remove the relations previously added to the relation graph
1054 * bb: the BB that must be processed
1055 * area: the current evaluation area (it contains the relation graph and
1056 * memory for all the evaluation contexts is already allocated)
1059 process_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoVariableRelationsEvaluationArea *area) {
1062 MonoAdditionalVariableRelationsForBB additional_relations;
1063 GSList *dominated_bb, *l;
1064 GSList *check_relations = NULL;
1066 if (TRACE_ABC_REMOVAL) {
1067 printf ("\nProcessing block %d [dfn %d]...\n", bb->block_num, bb->dfn);
1070 if (bb->region != -1)
1073 get_relations_from_previous_bb (area, bb, &additional_relations);
1074 if (TRACE_ABC_REMOVAL) {
1075 if (additional_relations.relation1.relation.relation != MONO_ANY_RELATION) {
1076 printf ("Adding relation 1 on variable %d: ", additional_relations.relation1.variable);
1077 print_summarized_value_relation (&(additional_relations.relation1.relation));
1080 if (additional_relations.relation2.relation.relation != MONO_ANY_RELATION) {
1081 printf ("Adding relation 2 on variable %d: ", additional_relations.relation2.variable);
1082 print_summarized_value_relation (&(additional_relations.relation2.relation));
1086 apply_change_to_evaluation_area (area, &(additional_relations.relation1));
1087 apply_change_to_evaluation_area (area, &(additional_relations.relation2));
1090 for (ins = bb->code; ins; ins = ins->next) {
1091 MonoAdditionalVariableRelation *rel;
1092 int array_var, index_var;
1094 if (TRACE_ABC_REMOVAL) {
1095 printf ("Processing instruction %d\n", inst_index);
1099 if (ins->opcode == OP_BOUNDS_CHECK) { /* Handle OP_LDELEMA2D, too */
1100 if (TRACE_ABC_REMOVAL) {
1101 printf ("Attempting check removal...\n");
1104 array_var = ins->sreg1;
1105 index_var = ins->sreg2;
1107 remove_abc_from_inst (ins, area);
1109 /* We can derive additional relations from the bounds check */
1110 if (ins->opcode != OP_NOP) {
1111 rel = (MonoAdditionalVariableRelation *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoAdditionalVariableRelation));
1112 rel->variable = index_var;
1113 rel->relation.relation = MONO_LT_RELATION;
1114 rel->relation.related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
1115 rel->relation.related_value.value.variable.variable = array_var;
1116 rel->relation.related_value.value.variable.delta = 0;
1118 apply_change_to_evaluation_area (area, rel);
1120 check_relations = g_slist_append_mempool (cfg->mempool, check_relations, rel);
1122 rel = (MonoAdditionalVariableRelation *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoAdditionalVariableRelation));
1123 rel->variable = index_var;
1124 rel->relation.relation = MONO_GE_RELATION;
1125 rel->relation.related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
1126 rel->relation.related_value.value.constant.value = 0;
1128 apply_change_to_evaluation_area (area, rel);
1130 check_relations = g_slist_append_mempool (cfg->mempool, check_relations, rel);
1134 if (ins->opcode == OP_CHECK_THIS) {
1135 if (eval_non_null (area, ins->sreg1)) {
1136 if (REPORT_ABC_REMOVAL)
1137 printf ("ARRAY-ACCESS: removed check_this instruction.\n");
1142 if (ins->opcode == OP_NOT_NULL)
1143 add_non_null (area, cfg, ins->sreg1, &check_relations);
1146 * FIXME: abcrem equates an array with its length,
1147 * so a = new int [100] implies a != null, but a = new int [0] doesn't.
1150 * Eliminate MONO_INST_FAULT flags if possible.
1152 if (COMPILE_LLVM (cfg) && (ins->opcode == OP_LDLEN ||
1153 ins->opcode == OP_BOUNDS_CHECK ||
1154 ins->opcode == OP_STRLEN ||
1155 (MONO_IS_LOAD_MEMBASE (ins) && (ins->flags & MONO_INST_FAULT)) ||
1156 (MONO_IS_STORE_MEMBASE (ins) && (ins->flags & MONO_INST_FAULT)))) {
1159 if (MONO_IS_STORE_MEMBASE (ins))
1160 reg = ins->inst_destbasereg;
1161 else if (MONO_IS_LOAD_MEMBASE (ins))
1162 reg = ins->inst_basereg;
1167 * This doesn't work because LLVM can move the non-faulting loads before the faulting
1168 * ones (test_0_llvm_moving_faulting_loads ()).
1169 * So only do it if we know the load cannot be moved before the instruction which ensures it is not
1170 * null (i.e. the def of its sreg).
1172 if (area->defs [reg] && area->defs [reg]->opcode == OP_NEWARR) {
1173 if (REPORT_ABC_REMOVAL)
1174 printf ("ARRAY-ACCESS: removed MONO_INST_FAULT flag.\n");
1175 ins->flags &= ~MONO_INST_FAULT;
1178 if (eval_non_null (area, reg)) {
1179 if (REPORT_ABC_REMOVAL)
1180 printf ("ARRAY-ACCESS: removed MONO_INST_FAULT flag.\n");
1181 ins->flags &= ~MONO_INST_FAULT;
1183 add_non_null (area, cfg, reg, &check_relations);
1189 if (TRACE_ABC_REMOVAL) {
1190 printf ("Processing block %d [dfn %d] done.\n", bb->block_num, bb->dfn);
1193 for (dominated_bb = bb->dominated; dominated_bb != NULL; dominated_bb = dominated_bb->next) {
1194 process_block (cfg, (MonoBasicBlock*) (dominated_bb->data), area);
1197 for (l = check_relations; l; l = l->next)
1198 remove_change_from_evaluation_area ((MonoAdditionalVariableRelation *)l->data);
1200 remove_change_from_evaluation_area (&(additional_relations.relation1));
1201 remove_change_from_evaluation_area (&(additional_relations.relation2));
1204 static MonoIntegerValueKind
1205 type_to_value_kind (MonoType *type)
1208 return MONO_UNKNOWN_INTEGER_VALUE;
1209 switch (type->type) {
1211 return MONO_INTEGER_VALUE_SIZE_1;
1214 return MONO_UNSIGNED_INTEGER_VALUE_SIZE_1;
1217 return MONO_INTEGER_VALUE_SIZE_2;
1220 return MONO_UNSIGNED_INTEGER_VALUE_SIZE_2;
1223 return MONO_INTEGER_VALUE_SIZE_4;
1226 return MONO_UNSIGNED_INTEGER_VALUE_SIZE_4;
1229 return (MonoIntegerValueKind)SIZEOF_VOID_P;
1232 return (MonoIntegerValueKind)(MONO_UNSIGNED_VALUE_FLAG | SIZEOF_VOID_P);
1235 return MONO_INTEGER_VALUE_SIZE_8;
1238 return MONO_UNSIGNED_INTEGER_VALUE_SIZE_8;
1240 return MONO_UNKNOWN_INTEGER_VALUE;
1245 * mono_perform_abc_removal:
1246 * \param cfg Control Flow Graph
1248 * Performs the ABC removal from a cfg in SSA form.
1249 * It does the following:
1250 * - Prepare the evaluation area
1251 * - Allocate memory for the relation graph in the evaluation area
1252 * (of course, only for variable definitions) and summarize there all
1253 * variable definitions
1254 * - Allocate memory for the evaluation contexts in the evaluation area
1255 * - Recursively process all the BBs in the dominator tree (it is enough
1256 * to invoke the processing on the entry BB)
1258 * cfg: the method code
1261 mono_perform_abc_removal (MonoCompile *cfg)
1263 MonoVariableRelationsEvaluationArea area;
1267 verbose_level = cfg->verbose_level;
1269 if (TRACE_ABC_REMOVAL) {
1270 printf ("\nRemoving array bound checks in %s\n", mono_method_full_name (cfg->method, TRUE));
1274 area.relations = (MonoSummarizedValueRelation *)
1275 mono_mempool_alloc (cfg->mempool, sizeof (MonoSummarizedValueRelation) * (cfg->next_vreg) * 2);
1277 area.contexts = (MonoRelationsEvaluationContext *)
1278 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRelationsEvaluationContext) * (cfg->next_vreg));
1280 area.statuses = (MonoRelationsEvaluationStatus *)
1281 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRelationsEvaluationStatus) * (cfg->next_vreg));
1283 area.variable_value_kind = (MonoIntegerValueKind *)
1284 mono_mempool_alloc (cfg->mempool, sizeof (MonoIntegerValueKind) * (cfg->next_vreg));
1285 area.defs = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * cfg->next_vreg);
1286 for (i = 0; i < cfg->next_vreg; i++) {
1287 area.variable_value_kind [i] = MONO_UNKNOWN_INTEGER_VALUE;
1288 area.relations [i].relation = MONO_EQ_RELATION;
1289 area.relations [i].relation_is_static_definition = TRUE;
1290 MAKE_VALUE_ANY (area.relations [i].related_value);
1291 area.relations [i].next = NULL;
1292 area.defs [i] = NULL;
1295 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1298 if (TRACE_ABC_REMOVAL)
1299 printf ("\nABCREM BLOCK %d:\n", bb->block_num);
1301 for (ins = bb->code; ins; ins = ins->next) {
1302 const char *spec = INS_INFO (ins->opcode);
1305 if (spec [MONO_INST_DEST] == ' ' || MONO_IS_STORE_MEMBASE (ins))
1308 MONO_INS_FOR_EACH_REG (ins, idx, reg) {
1309 MonoInst *var = get_vreg_to_inst (cfg, *reg);
1310 if (var && (!MONO_VARINFO (cfg, var->inst_c0)->def))
1313 if (idx < MONO_INST_LEN) {
1314 if (TRACE_ABC_REMOVAL)
1315 printf ("Global register %d is not in the SSA form, skipping.\n", *reg);
1319 if (spec [MONO_INST_DEST] == 'i') {
1320 MonoIntegerValueKind effective_value_kind;
1321 MonoRelationsEvaluationRange range;
1322 MonoSummarizedValueRelation *type_relation;
1325 if (TRACE_ABC_REMOVAL)
1326 mono_print_ins (ins);
1328 var = get_vreg_to_inst (cfg, ins->dreg);
1330 area.variable_value_kind [ins->dreg] = type_to_value_kind (var->inst_vtype);
1332 effective_value_kind = get_relation_from_ins (&area, ins, &area.relations [ins->dreg], area.variable_value_kind [ins->dreg]);
1334 MONO_MAKE_RELATIONS_EVALUATION_RANGE_WEAK (range);
1335 apply_value_kind_to_range (&range, area.variable_value_kind [ins->dreg]);
1336 apply_value_kind_to_range (&range, effective_value_kind);
1338 if (range.upper < INT_MAX) {
1339 type_relation = (MonoSummarizedValueRelation *) mono_mempool_alloc (cfg->mempool, sizeof (MonoSummarizedValueRelation));
1340 type_relation->relation = MONO_LE_RELATION;
1341 type_relation->related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
1342 type_relation->related_value.value.constant.value = range.upper;
1343 type_relation->relation_is_static_definition = TRUE;
1344 type_relation->next = area.relations [ins->dreg].next;
1345 area.relations [ins->dreg].next = type_relation;
1346 if (TRACE_ABC_REMOVAL) {
1347 printf ("[var%d <= %d]", ins->dreg, range.upper);
1350 if (range.lower > INT_MIN) {
1351 type_relation = (MonoSummarizedValueRelation *) mono_mempool_alloc (cfg->mempool, sizeof (MonoSummarizedValueRelation));
1352 type_relation->relation = MONO_GE_RELATION;
1353 type_relation->related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
1354 type_relation->related_value.value.constant.value = range.lower;
1355 type_relation->relation_is_static_definition = TRUE;
1356 type_relation->next = area.relations [ins->dreg].next;
1357 area.relations [ins->dreg].next = type_relation;
1358 if (TRACE_ABC_REMOVAL) {
1359 printf ("[var%d >= %d]", ins->dreg, range.lower);
1362 if (TRACE_ABC_REMOVAL) {
1363 printf ("Summarized variable %d: ", ins->dreg);
1364 print_summarized_value (&(area.relations [ins->dreg].related_value));
1371 /* Add symmetric relations */
1372 for (i = 0; i < cfg->next_vreg; i++) {
1373 if (area.relations [i].related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
1374 int related_index = cfg->next_vreg + i;
1375 int related_variable = area.relations [i].related_value.value.variable.variable;
1377 area.relations [related_index].relation = MONO_EQ_RELATION;
1378 area.relations [related_index].relation_is_static_definition = TRUE;
1379 area.relations [related_index].related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
1380 area.relations [related_index].related_value.value.variable.variable = i;
1381 area.relations [related_index].related_value.value.variable.delta = - area.relations [i].related_value.value.variable.delta;
1383 area.relations [related_index].next = area.relations [related_variable].next;
1384 area.relations [related_variable].next = &(area.relations [related_index]);
1386 if (TRACE_ABC_REMOVAL) {
1387 printf ("Added symmetric summarized value for variable variable %d (to %d): ", i, related_variable);
1388 print_summarized_value (&(area.relations [related_index].related_value));
1394 process_block (cfg, cfg->bblocks [0], &area);
1397 #else /* !DISABLE_JIT */
1399 MONO_EMPTY_SOURCE_FILE (abcremoval);
1401 #endif /* !DISABLE_JIT */