2 * abcremoval.c: Array bounds check removal
5 * Massimiliano Mantione (massi@ximian.com)
7 * (C) 2004 Ximian, Inc. http://www.ximian.com
12 #include <mono/metadata/debug-helpers.h>
13 #include <mono/metadata/mempool.h>
14 #include <mono/metadata/opcodes.h>
18 #include "abcremoval.h"
20 extern guint8 mono_burg_arity [];
22 #define TRACE_ABC_REMOVAL (verbose_level > 2)
23 #define REPORT_ABC_REMOVAL (verbose_level > 0)
26 * A little hack for the verbosity level.
27 * The verbosity level is stored in the cfg, but not all functions that must
28 * print something see the cfg, so we store the verbosity level here at the
29 * beginning of the algorithm.
30 * This is not thread safe (does not handle correctly different verbosity
31 * levels in different threads), and is not exact in case of dynamic changes
32 * of the verbosity level...
33 * Anyway, this is not needed, all that can happen is that something more
34 * (or less) is logged, the result is in any case correct.
36 static int verbose_level;
39 #define RELATION_BETWEEN_VALUES(value,related_value) (\
40 ((value) > (related_value))? MONO_GT_RELATION :\
41 (((value) < (related_value))? MONO_LT_RELATION : MONO_EQ_RELATION))
43 #define MAKE_VALUE_ANY(v) do{\
44 (v).type = MONO_ANY_SUMMARIZED_VALUE;\
47 #define MAKE_VALUE_RELATION_ANY(r) do{\
48 (r)->relation = MONO_ANY_RELATION;\
49 MAKE_VALUE_ANY((r)->related_value);\
52 #define INITIALIZE_VALUE_RELATION(r) do{\
53 MAKE_VALUE_RELATION_ANY((r));\
57 #define MONO_NEGATED_RELATION(r) ((~(r))&MONO_ANY_RELATION)
58 #define MONO_SYMMETRIC_RELATION(r) (((r)&MONO_EQ_RELATION)|(((r)&MONO_LT_RELATION)<<1)|((r&MONO_GT_RELATION)>>1))
63 print_relation (int relation) {
66 if (relation & MONO_LT_RELATION) {
70 if (relation & MONO_EQ_RELATION) {
77 if (relation & MONO_GT_RELATION) {
88 print_summarized_value (MonoSummarizedValue *value) {
89 switch (value->type) {
90 case MONO_ANY_SUMMARIZED_VALUE:
93 case MONO_CONSTANT_SUMMARIZED_VALUE:
94 printf ("CONSTANT %d", value->value.constant.value);
96 case MONO_VARIABLE_SUMMARIZED_VALUE:
97 printf ("VARIABLE %d, delta %d", value->value.variable.variable, value->value.variable.delta);
99 case MONO_PHI_SUMMARIZED_VALUE: {
102 for (phi = 0; phi < value->value.phi.number_of_alternatives; phi++) {
103 if (phi) printf (",");
104 printf ("%d", value->value.phi.phi_alternatives [phi]);
110 g_assert_not_reached ();
115 print_summarized_value_relation (MonoSummarizedValueRelation *relation) {
116 printf ("Relation ");
117 print_relation (relation->relation);
118 printf (" with value ");
119 print_summarized_value (&(relation->related_value));
124 print_summarized_value_relation_chain (MonoSummarizedValueRelation *relation) {
125 printf ("Relations:\n");
127 print_summarized_value_relation (relation);
129 relation = relation->next;
135 print_evaluation_context_status (MonoRelationsEvaluationStatus status) {
136 if (status == MONO_RELATIONS_EVALUATION_NOT_STARTED) {
137 printf ("EVALUATION_NOT_STARTED");
139 gboolean print_or = FALSE;
142 if (status & MONO_RELATIONS_EVALUATION_IN_PROGRESS) {
143 if (print_or) printf ("|");
144 printf ("EVALUATION_IN_PROGRESS");
147 if (status & MONO_RELATIONS_EVALUATION_COMPLETED) {
148 if (print_or) printf ("|");
149 printf ("EVALUATION_COMPLETED");
152 if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING) {
153 if (print_or) printf ("|");
154 printf ("RECURSIVELY_ASCENDING");
157 if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING) {
158 if (print_or) printf ("|");
159 printf ("RECURSIVELY_DESCENDING");
162 if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE) {
163 if (print_or) printf ("|");
164 printf ("RECURSIVELY_INDEFINITE");
173 print_evaluation_context_ranges (MonoRelationsEvaluationRanges *ranges) {
174 printf ("(ranges: zero [%d,%d], variable [%d,%d])", ranges->zero.lower, ranges->zero.upper, ranges->variable.lower, ranges->variable.upper);
178 print_evaluation_context (MonoRelationsEvaluationContext *context) {
179 printf ("Context status: ");
180 print_evaluation_context_status (context->status);
181 if (context->status & (MONO_RELATIONS_EVALUATION_IN_PROGRESS|MONO_RELATIONS_EVALUATION_COMPLETED)) {
182 print_evaluation_context_ranges (&(context->ranges));
189 print_evaluation_area (MonoVariableRelationsEvaluationArea *area) {
191 printf ("Dump of evaluation area (%d variables):\n", area->cfg->num_varinfo);
192 for (i = 0; i < area->cfg->num_varinfo; i++) {
193 printf ("Variable %d: ", i);
194 print_evaluation_context (&(area->contexts [i]));
195 print_summarized_value_relation_chain (&(area->relations [i]));
200 print_evaluation_area_contexts (MonoVariableRelationsEvaluationArea *area) {
202 printf ("Dump of evaluation area contexts (%d variables):\n", area->cfg->num_varinfo);
203 for (i = 0; i < area->cfg->num_varinfo; i++) {
204 printf ("Variable %d: ", i);
205 print_evaluation_context (&(area->contexts [i]));
211 * Given a MonoInst, if it is a store to a variable return the MonoInst that
212 * represents the stored value.
213 * If anything goes wrong, return NULL.
214 * store: the MonoInst that should be a store
215 * expected_variable_index: the variable where the value should be stored
216 * return: either the stored value, or NULL
219 get_variable_value_from_store_instruction (MonoInst *store, int expected_variable_index) {
220 switch (store->opcode) {
229 if (TRACE_ABC_REMOVAL) {
230 printf ("[store instruction found]");
232 if (store->inst_left->opcode == OP_LOCAL) {
233 int variable_index = store->inst_left->inst_c0;
234 if (TRACE_ABC_REMOVAL) {
235 printf ("[value put in local %d (expected %d)]", variable_index, expected_variable_index);
237 if (variable_index == expected_variable_index) {
238 return store->inst_right;
254 * Given a MonoInst representing a value, store it in "summarized" form.
255 * result: the "summarized" value
258 summarize_value (MonoInst *value, MonoSummarizedValue *result) {
259 switch (value->opcode) {
261 result->type = MONO_CONSTANT_SUMMARIZED_VALUE;
262 result->value.constant.value = value->inst_c0;
266 result->type = MONO_VARIABLE_SUMMARIZED_VALUE;
267 result->value.variable.variable = value->inst_c0;
268 result->value.variable.delta = 0;
277 if ((value->inst_left->opcode == OP_LOCAL) || (value->inst_left->opcode == OP_ARG)) {
278 summarize_value (value->inst_left, result);
280 MAKE_VALUE_ANY (*result);
284 MonoSummarizedValue left_value;
285 MonoSummarizedValue right_value;
286 summarize_value (value->inst_left, &left_value);
287 summarize_value (value->inst_right, &right_value);
289 if (left_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
290 if (right_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) {
291 result->type = MONO_VARIABLE_SUMMARIZED_VALUE;
292 result->value.variable.variable = left_value.value.variable.variable;
293 result->value.variable.delta = left_value.value.variable.delta + right_value.value.constant.value;
295 MAKE_VALUE_ANY (*result);
297 } else if (right_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
298 if (left_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) {
299 result->type = MONO_VARIABLE_SUMMARIZED_VALUE;
300 result->value.variable.variable = right_value.value.variable.variable;
301 result->value.variable.delta = left_value.value.constant.value + right_value.value.variable.delta;
303 MAKE_VALUE_ANY (*result);
305 } else if ((right_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) && (left_value.type == MONO_CONSTANT_SUMMARIZED_VALUE)) {
306 /* This should not happen if constant folding has been done */
307 result->type = MONO_CONSTANT_SUMMARIZED_VALUE;
308 result->value.constant.value = left_value.value.constant.value + right_value.value.constant.value;
310 MAKE_VALUE_ANY (*result);
315 MonoSummarizedValue left_value;
316 MonoSummarizedValue right_value;
317 summarize_value (value->inst_left, &left_value);
318 summarize_value (value->inst_right, &right_value);
320 if (left_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
321 if (right_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) {
322 result->type = MONO_VARIABLE_SUMMARIZED_VALUE;
323 result->value.variable.variable = left_value.value.variable.variable;
324 result->value.variable.delta = left_value.value.variable.delta - right_value.value.constant.value;
326 MAKE_VALUE_ANY (*result);
328 } else if ((right_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) && (left_value.type == MONO_CONSTANT_SUMMARIZED_VALUE)) {
329 /* This should not happen if constant folding has been done */
330 result->type = MONO_CONSTANT_SUMMARIZED_VALUE;
331 result->value.constant.value = left_value.value.constant.value - right_value.value.constant.value;
333 MAKE_VALUE_ANY (*result);
338 summarize_value (value->inst_newa_len, result);
341 summarize_value (value->inst_left, result);
344 result->type = MONO_PHI_SUMMARIZED_VALUE;
345 result->value.phi.number_of_alternatives = *(value->inst_phi_args);
346 result->value.phi.phi_alternatives = value->inst_phi_args + 1;
349 MAKE_VALUE_ANY (*result);
353 static MonoValueRelation
354 get_relation_from_branch_instruction (int opcode) {
357 return MONO_EQ_RELATION;
360 return MONO_LT_RELATION;
363 return MONO_LE_RELATION;
366 return MONO_GT_RELATION;
369 return MONO_GE_RELATION;
371 return MONO_NE_RELATION;
373 return MONO_ANY_RELATION;
378 * Given a BB, find its entry condition and put its relations in a
379 * "MonoAdditionalVariableRelationsForBB" structure.
381 * relations: the resulting relations (entry condition of the given BB)
384 get_relations_from_previous_bb (MonoBasicBlock *bb, MonoAdditionalVariableRelationsForBB *relations) {
385 MonoBasicBlock *in_bb;
387 MonoValueRelation branch_relation;
388 MonoValueRelation symmetric_relation;
390 INITIALIZE_VALUE_RELATION (&(relations->relation1.relation));
391 relations->relation1.relation.relation_is_static_definition = FALSE;
392 relations->relation1.insertion_point = NULL;
393 relations->relation1.variable = -1;
394 INITIALIZE_VALUE_RELATION (&(relations->relation2.relation));
395 relations->relation2.relation.relation_is_static_definition = FALSE;
396 relations->relation2.insertion_point = NULL;
397 relations->relation2.variable = -1;
400 if (bb->in_count == 1) { /* Should write the code to "sum" conditions... */
401 in_bb = bb->in_bb [0];
402 branch = in_bb->last_ins;
403 if (branch == NULL) return;
404 branch_relation = get_relation_from_branch_instruction (branch->opcode);
405 if ((branch_relation != MONO_ANY_RELATION) && (branch->inst_left->opcode == OP_COMPARE)) {
406 MonoSummarizedValue left_value;
407 MonoSummarizedValue right_value;
410 if (branch->inst_true_bb == bb) {
412 } else if (branch->inst_false_bb == bb) {
416 g_assert_not_reached ();
420 branch_relation = MONO_NEGATED_RELATION (branch_relation);
422 symmetric_relation = MONO_SYMMETRIC_RELATION (branch_relation);
424 summarize_value (branch->inst_left->inst_left, &left_value);
425 summarize_value (branch->inst_left->inst_right, &right_value);
427 if ((left_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) && ((right_value.type == MONO_VARIABLE_SUMMARIZED_VALUE)||(right_value.type == MONO_CONSTANT_SUMMARIZED_VALUE))) {
428 relations->relation1.variable = left_value.value.variable.variable;
429 relations->relation1.relation.relation = branch_relation;
430 relations->relation1.relation.related_value = right_value;
431 if (right_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) {
432 relations->relation1.relation.related_value.value.constant.value -= left_value.value.variable.delta;
434 relations->relation1.relation.related_value.value.variable.delta -= left_value.value.variable.delta;
437 if ((right_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) && ((left_value.type == MONO_VARIABLE_SUMMARIZED_VALUE)||(left_value.type == MONO_CONSTANT_SUMMARIZED_VALUE))) {
438 relations->relation2.variable = right_value.value.variable.variable;
439 relations->relation2.relation.relation = symmetric_relation;
440 relations->relation2.relation.related_value = left_value;
441 if (left_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) {
442 relations->relation2.relation.related_value.value.constant.value -= right_value.value.variable.delta;
444 relations->relation2.relation.related_value.value.variable.delta -= right_value.value.variable.delta;
453 * Add the given relations to the evaluation area.
454 * area: the evaluation area
455 * change: the relations that must be added
458 apply_change_to_evaluation_area (MonoVariableRelationsEvaluationArea *area, MonoAdditionalVariableRelation *change) {
459 MonoSummarizedValueRelation *base_relation;
461 if (change->relation.relation != MONO_ANY_RELATION) {
462 base_relation = &(area->relations [change->variable]);
463 while ((base_relation->next != NULL) && (base_relation->next->relation_is_static_definition)) {
464 base_relation = base_relation->next;
466 change->insertion_point = base_relation;
467 change->relation.next = base_relation->next;
468 base_relation->next = &(change->relation);
473 * Remove the given relation from the evaluation area.
474 * change: the relation that must be removed
477 remove_change_from_evaluation_area (MonoAdditionalVariableRelation *change) {
478 if (change->insertion_point != NULL) {
479 change->insertion_point->next = change->relation.next;
480 change->relation.next = NULL;
486 clean_contexts (MonoRelationsEvaluationContext *contexts, int number) {
488 for (i = 0; i < number; i++) {
489 contexts [i].status = MONO_RELATIONS_EVALUATION_NOT_STARTED;
495 * Perform the intersection of a range and a constant value (taking into
496 * account the relation that the value has with the range).
497 * range: the range that will be intersected with the value
498 * value: the value that will be intersected with the range
499 * relation: the relation between the range and the value
502 intersect_value( MonoRelationsEvaluationRange *range, int value, MonoValueRelation relation ) {
504 case MONO_NO_RELATION:
505 MONO_MAKE_RELATIONS_EVALUATION_RANGE_IMPOSSIBLE (*range);
507 case MONO_ANY_RELATION:
509 case MONO_EQ_RELATION:
510 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, value);
511 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, value);
513 case MONO_NE_RELATION: {
514 /* IMPROVEMENT Figure this out! (ignoring it is safe anyway) */
517 case MONO_LT_RELATION:
518 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (value));
520 case MONO_LE_RELATION:
521 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, value);
523 case MONO_GT_RELATION:
524 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (value));
526 case MONO_GE_RELATION:
527 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, value);
530 g_assert_not_reached();
536 * Perform the intersection of two pairs of ranges (taking into account the
537 * relation between the ranges and a given delta).
538 * ranges: the ranges that will be intersected
539 * other_ranges the other ranges that will be intersected
540 * delta: the delta between the pairs of ranges
541 * relation: the relation between the pairs of ranges
544 intersect_ranges( MonoRelationsEvaluationRanges *ranges, MonoRelationsEvaluationRanges *other_ranges, int delta, MonoValueRelation relation ) {
547 case MONO_NO_RELATION:
548 MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (*ranges);
550 case MONO_ANY_RELATION:
552 case MONO_EQ_RELATION:
553 MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (*ranges, *other_ranges);
555 case MONO_NE_RELATION: {
556 /* FIXME Figure this out! (ignoring it is safe anyway) */
559 case MONO_LT_RELATION:
560 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->zero.upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->zero.upper));
561 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->variable.upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->variable.upper));
563 case MONO_LE_RELATION:
564 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->zero.upper, other_ranges->zero.upper);
565 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->variable.upper, other_ranges->variable.upper);
567 case MONO_GT_RELATION:
568 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->zero.lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->zero.lower));
569 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->variable.lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->variable.lower));
571 case MONO_GE_RELATION:
572 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->zero.lower, other_ranges->zero.lower);
573 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->variable.lower, other_ranges->variable.lower);
576 g_assert_not_reached();
579 MonoRelationsEvaluationRanges translated_ranges = *other_ranges;
580 MONO_ADD_DELTA_SAFELY_TO_RANGES (translated_ranges, delta);
581 intersect_ranges( ranges, &translated_ranges, FALSE, relation );
586 * Recursive method that traverses the relation graph to evaluate the
587 * relation between two variables.
588 * At the end of the execution, the resulting ranges are in the context of
589 * the "starting" variable.
590 * area: the current evaluation area (it contains the relation graph and
591 * memory for all the evaluation contexts is already allocated)
592 * variable: starting variable (the value ranges in its context are the result
593 * of the execution of this procedure)
594 * target_variable: the variable with respect to which the starting variable
595 * is evaluated (tipically the starting variable is the index
596 * and the target one is the array (which means its length))
597 * father_context: the previous evaluation context in recursive invocations
598 * (or NULL for the first invocation)
601 evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *area, int variable, int target_variable, MonoRelationsEvaluationContext *father_context) {
602 MonoRelationsEvaluationContext *context = &(area->contexts [variable]);
604 // First of all, we check the evaluation status
605 // (what must be done is *very* different in each case)
606 switch (context->status) {
607 case MONO_RELATIONS_EVALUATION_NOT_STARTED: {
608 MonoSummarizedValueRelation *relation = &(area->relations [variable]);
610 if (TRACE_ABC_REMOVAL) {
611 printf ("Evaluating varible %d (target variable %d)\n", variable, target_variable);
612 print_summarized_value_relation (relation);
616 // We properly inizialize the context
617 context->status = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
618 context->father = father_context;
619 MONO_MAKE_RELATIONS_EVALUATION_RANGES_WEAK (context->ranges);
621 // If we have found the target variable, we can set the range
622 // related to it in the context to "equal" (which is [0,0])
623 if (variable == target_variable) {
624 if (TRACE_ABC_REMOVAL) {
625 printf ("Target variable reached (%d), continuing to evaluate relations with constants\n", variable);
627 context->ranges.variable.lower = 0;
628 context->ranges.variable.upper = 0;
631 // Examine all relations for this variable (scan the list)
632 // The contribute of each relation will be intersected (logical and)
633 while (relation != NULL) {
634 context->current_relation = relation;
636 if (TRACE_ABC_REMOVAL) {
637 printf ("Processing (%d): ", variable);
638 print_summarized_value_relation (relation);
642 // We decie what to do according the the type of the related value
643 switch (relation->related_value.type) {
644 case MONO_ANY_SUMMARIZED_VALUE:
645 // No added information, skip it
647 case MONO_CONSTANT_SUMMARIZED_VALUE:
648 // Intersect range with constant (taking into account the relation)
649 intersect_value (&(context->ranges.zero), relation->related_value.value.constant.value, relation->relation);
651 case MONO_VARIABLE_SUMMARIZED_VALUE:
652 // Generally, evaluate related variable and intersect ranges.
653 // However, some check is necessary...
655 // If the relation is "ANY", nothing to do (no added information)
656 if (relation->relation != MONO_ANY_RELATION) {
657 gssize related_variable = relation->related_value.value.variable.variable;
658 MonoRelationsEvaluationContext *related_context = &(area->contexts [related_variable]);
660 // The second condition in the "or" avoids messing with "back edges" in the graph traversal
661 // (they are simply ignored instead of triggering the handling of recursion)
662 if ( (related_context->status == MONO_RELATIONS_EVALUATION_NOT_STARTED) || !
663 ((related_context->current_relation->related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) &&
664 (related_context->current_relation->related_value.value.variable.variable == variable))) {
665 // Evaluate the related variable
666 evaluate_relation_with_target_variable (area, related_variable, target_variable, context);
668 // Check if we are part of a recursive loop
669 if (context->status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
670 if (TRACE_ABC_REMOVAL) {
671 printf ("Recursivity detected for varible %d (target variable %d), status ", variable, target_variable);
672 print_evaluation_context_status (context->status);
675 // If we are, check if the evaluation of the related variable is complete
676 if (related_context->status == MONO_RELATIONS_EVALUATION_COMPLETED) {
677 // If it is complete, we are part of a recursive definition.
678 // Since it is a *definition* (and definitions are evaluated *before*
679 // conditions because they are first in the list), intersection is not
680 // strictly necessary, we simply copy the ranges and apply the delta
681 context->ranges = related_context->ranges;
682 MONO_ADD_DELTA_SAFELY_TO_RANGES (context->ranges, relation->related_value.value.variable.delta);
683 context->status = MONO_RELATIONS_EVALUATION_COMPLETED;
684 if (TRACE_ABC_REMOVAL) {
685 printf (", ranges already computed, result: \n");
686 print_evaluation_context_ranges (&(context->ranges));
687 printf (" (delta is %d)\n", relation->related_value.value.variable.delta);
690 // If it is not complete, do nothing (we do not have enough information)
691 if (TRACE_ABC_REMOVAL) {
692 printf (", ranges not computed\n");
696 // If we are not (the common case) intersect the result
697 intersect_ranges( &(context->ranges), &(related_context->ranges), relation->related_value.value.variable.delta, relation->relation );
700 if (TRACE_ABC_REMOVAL) {
701 printf ("Relation is a back-edge in this traversal, skipping\n");
706 case MONO_PHI_SUMMARIZED_VALUE: {
707 // We must compute all PHI alternatives, combining the results (with a union, which is a logical "or"),
708 // and intersect this result with the ranges in the context; we must also take into account recursions
709 // (with loops that can be ascending, descending, or indefinite)
710 MonoRelationsEvaluationRanges phi_ranges;
712 gboolean is_ascending = FALSE;
713 gboolean is_descending = FALSE;
715 MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (phi_ranges);
716 for (phi = 0; phi < relation->related_value.value.phi.number_of_alternatives; phi++) {
717 int phi_alternative = relation->related_value.value.phi.phi_alternatives [phi];
718 evaluate_relation_with_target_variable (area, phi_alternative, target_variable, context);
720 // This means we are part of a recursive loop
721 if (context->status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
722 if (TRACE_ABC_REMOVAL) {
723 printf ("Recursivity detected for varible %d (target variable %d), status ", variable, target_variable);
724 print_evaluation_context_status (context->status);
727 if (context->status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING) {
730 if (context->status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING) {
731 is_descending = TRUE;
733 if (context->status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE) {
735 is_descending = TRUE;
738 // Clear "recursivity" bits in the status (recursion has been handled)
739 context->status = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
741 MONO_RELATIONS_EVALUATION_RANGES_UNION (phi_ranges, area->contexts [phi_alternative].ranges);
745 // Apply the effects of all recursive loops
747 phi_ranges.zero.upper = INT_MAX;
748 phi_ranges.variable.upper = INT_MAX;
751 phi_ranges.zero.lower = INT_MIN;
752 phi_ranges.variable.lower = INT_MIN;
755 // Intersect final result
756 MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (context->ranges, phi_ranges);
760 g_assert_not_reached();
763 // Pass to next relation
764 relation = relation->next;
767 // Check if any recursivity bits are still in the status, and in any case clear them
768 if (context->status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
769 if (TRACE_ABC_REMOVAL) {
770 printf ("Recursivity for varible %d (target variable %d) discards computation, status ", variable, target_variable);
771 print_evaluation_context_status (context->status);
774 // If yes, we did not have enough information (most likely we were evaluated inside a PHI, but we also
775 // depended on the same PHI, which was still in evaluation...), so clear the status to "NOT_STARTED"
776 // (if we will be evaluated again, the PHI will be already done, so our evaluation will succeed)
777 context->status = MONO_RELATIONS_EVALUATION_NOT_STARTED;
779 if (TRACE_ABC_REMOVAL) {
780 printf ("Ranges for varible %d (target variable %d) computated: ", variable, target_variable);
781 print_evaluation_context_ranges (&(context->ranges));
784 // If not (the common case) the evaluation is complete, and the result is in the context
785 context->status = MONO_RELATIONS_EVALUATION_COMPLETED;
789 case MONO_RELATIONS_EVALUATION_IN_PROGRESS: {
790 // This means we are in a recursive loop
791 MonoRelationsEvaluationContext *current_context = father_context;
792 MonoRelationsEvaluationContext *last_context = context->father;
793 gboolean evaluation_can_be_recursive = TRUE;
794 gboolean evaluation_is_definition = TRUE;
797 if (TRACE_ABC_REMOVAL) {
798 printf ("Evaluation of varible %d (target variable %d) already in progress\n", variable, target_variable);
799 print_evaluation_context (context);
800 print_summarized_value_relation (context->current_relation);
804 // We must check if the loop can be a recursive definition (we scan the whole loop)
805 while (current_context != last_context) {
806 if (current_context == NULL) {
807 printf ("Broken recursive ring in ABC removal\n");
808 g_assert_not_reached ();
811 if (current_context->current_relation->relation_is_static_definition) {
812 if (current_context->current_relation->related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
813 path_value += current_context->current_relation->related_value.value.variable.delta;
814 } else if (current_context->current_relation->related_value.type != MONO_PHI_SUMMARIZED_VALUE) {
815 evaluation_can_be_recursive = FALSE;
818 evaluation_is_definition = FALSE;
819 evaluation_can_be_recursive = FALSE;
822 current_context = current_context->father;
825 // If this is a recursive definition, we properly flag the status in all the involved contexts
826 if (evaluation_is_definition) {
827 MonoRelationsEvaluationStatus recursive_status;
828 if (evaluation_can_be_recursive) {
829 if (path_value > 0) {
830 recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING;
831 } else if (path_value < 0) {
832 recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING;
834 recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE;
837 recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE;
840 if (TRACE_ABC_REMOVAL) {
841 printf ("Recursivity accepted (");
842 print_evaluation_context_status (recursive_status);
846 current_context = father_context;
847 while (current_context != last_context) {
848 current_context->status |= recursive_status;
849 current_context = current_context->father;
852 if (TRACE_ABC_REMOVAL) {
853 printf ("Recursivity rejected (some relation in the cycle is not a defintion)\n");
858 case MONO_RELATIONS_EVALUATION_COMPLETED: {
862 if (TRACE_ABC_REMOVAL) {
863 printf ("Varible %d (target variable %d) already in a recursive ring, skipping\n", variable, target_variable);
864 print_evaluation_context (context);
865 print_summarized_value_relation (context->current_relation);
875 * Attempt the removal of bounds checks from a MonoInst.
877 * area: the current evaluation area (it contains the relation graph and
878 * memory for all the evaluation contexts is already allocated)
881 remove_abc_from_inst (MonoInst *inst, MonoVariableRelationsEvaluationArea *area) {
882 if (inst->opcode == CEE_LDELEMA) {
883 MonoInst *array_inst = inst->inst_left;
884 MonoInst *index_inst = inst->inst_right;
886 // The array must be a local variable and the index must be a properly summarized value
887 if ((array_inst->opcode == CEE_LDIND_REF) &&
888 ((array_inst->inst_left->opcode == OP_LOCAL)||(array_inst->inst_left->opcode == OP_ARG))) {
889 gssize array_variable = array_inst->inst_left->inst_c0;
890 MonoRelationsEvaluationContext *array_context = &(area->contexts [array_variable]);
891 MonoSummarizedValue index_value;
893 summarize_value (index_inst, &index_value);
894 if (index_value.type == MONO_CONSTANT_SUMMARIZED_VALUE) {
895 // The easiest case: we just evaluate the array length, to see if it has some relation
896 // with the index constant, and act accordingly
898 clean_contexts (area->contexts, area->cfg->num_varinfo);
899 evaluate_relation_with_target_variable (area, array_variable, array_variable, NULL);
901 if ((index_value.value.constant.value >= 0) && (index_value.value.constant.value < array_context->ranges.zero.lower)) {
902 if (REPORT_ABC_REMOVAL) {
903 printf ("ARRAY-ACCESS: removed bounds check on array %d with constant index %d in method %s\n",
904 array_variable, index_value.value.constant.value, mono_method_full_name (area->cfg->method, TRUE));
906 inst->flags |= (MONO_INST_NORANGECHECK);
908 } else if (index_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
909 // The common case: we must evaluate both the index and the array length, and check for relevant
910 // relations both through variable definitions and as constant definitions
912 gssize index_variable = index_value.value.variable.variable;
913 MonoRelationsEvaluationContext *index_context = &(area->contexts [index_variable]);
915 clean_contexts (area->contexts, area->cfg->num_varinfo);
917 evaluate_relation_with_target_variable (area, index_variable, array_variable, NULL);
918 evaluate_relation_with_target_variable (area, array_variable, array_variable, NULL);
920 MONO_SUB_DELTA_SAFELY_FROM_RANGES (index_context->ranges, index_value.value.variable.delta);
922 if (index_context->ranges.zero.lower >= 0) {
923 if (TRACE_ABC_REMOVAL) {
924 printf ("ARRAY-ACCESS: Removed lower bound check on array %d with index %d\n", array_variable, index_variable);
926 if ((index_context->ranges.variable.upper < 0)||(index_context->ranges.zero.upper < array_context->ranges.zero.lower)) {
927 if (REPORT_ABC_REMOVAL) {
928 printf ("ARRAY-ACCESS: removed bounds check on array %d with index %d in method %s\n",
929 array_variable, index_variable, mono_method_full_name (area->cfg->method, TRUE));
931 inst->flags |= (MONO_INST_NORANGECHECK);
934 if (TRACE_ABC_REMOVAL) {
935 if (index_context->ranges.variable.upper < 0) {
936 printf ("ARRAY-ACCESS: Removed upper bound check (through variable) on array %d with index %d\n", array_variable, index_variable);
938 if (index_context->ranges.zero.upper < array_context->ranges.zero.lower) {
939 printf ("ARRAY-ACCESS: Removed upper bound check (through constant) on array %d with index %d\n", array_variable, index_variable);
949 * Recursively scan a tree of MonoInst looking for array accesses.
950 * inst: the root of the MonoInst tree
951 * area: the current evaluation area (it contains the relation graph and
952 * memory for all the evaluation contexts is already allocated)
955 process_inst (MonoInst *inst, MonoVariableRelationsEvaluationArea *area) {
956 if (inst->opcode == CEE_LDELEMA) { /* Handle OP_LDELEMA2D, too */
957 if (TRACE_ABC_REMOVAL) {
958 printf ("Attempting check removal...\n");
961 remove_abc_from_inst (inst, area);
964 if (mono_burg_arity [inst->opcode]) {
965 process_inst (inst->inst_left, area);
966 if (mono_burg_arity [inst->opcode] > 1) {
967 process_inst (inst->inst_right, area);
976 * Process a BB removing bounds checks from array accesses.
977 * It does the following (in sequence):
978 * - Get the BB entry condition
979 * - Add its relations to the relation graph in the evaluation area
980 * - Process all the MonoInst trees in the BB
981 * - Recursively process all the children BBs in the dominator tree
982 * - Remove the relations previously added to the relation graph
984 * bb: the BB that must be processed
985 * area: the current evaluation area (it contains the relation graph and
986 * memory for all the evaluation contexts is already allocated)
989 process_block (MonoBasicBlock *bb, MonoVariableRelationsEvaluationArea *area) {
991 MonoInst *current_inst;
992 MonoAdditionalVariableRelationsForBB additional_relations;
995 if (TRACE_ABC_REMOVAL) {
996 printf ("Processing block %d [dfn %d]...\n", bb->block_num, bb->dfn);
999 get_relations_from_previous_bb (bb, &additional_relations);
1000 if (TRACE_ABC_REMOVAL) {
1001 if (additional_relations.relation1.relation.relation != MONO_ANY_RELATION) {
1002 printf ("Adding relation 1 on variable %d: ", additional_relations.relation1.variable);
1003 print_summarized_value_relation (&(additional_relations.relation1.relation));
1006 if (additional_relations.relation2.relation.relation != MONO_ANY_RELATION) {
1007 printf ("Adding relation 2 on variable %d: ", additional_relations.relation2.variable);
1008 print_summarized_value_relation (&(additional_relations.relation2.relation));
1012 apply_change_to_evaluation_area (area, &(additional_relations.relation1));
1013 apply_change_to_evaluation_area (area, &(additional_relations.relation2));
1016 current_inst = bb->code;
1017 while (current_inst != NULL) {
1018 if (TRACE_ABC_REMOVAL) {
1019 printf ("Processing instruction %d\n", inst_index);
1023 process_inst (current_inst, area);
1025 current_inst = current_inst->next;
1029 if (TRACE_ABC_REMOVAL) {
1030 printf ("Processing block %d [dfn %d] done.\n", bb->block_num, bb->dfn);
1033 for (dominated_bb = g_list_first (bb->dominated); dominated_bb != NULL; dominated_bb = g_list_next (dominated_bb)) {
1034 process_block ((MonoBasicBlock*) (dominated_bb->data), area);
1037 remove_change_from_evaluation_area (&(additional_relations.relation1));
1038 remove_change_from_evaluation_area (&(additional_relations.relation2));
1044 * mono_perform_abc_removal:
1045 * @cfg: Control Flow Graph
1047 * Performs the ABC removal from a cfg in SSA form.
1048 * It does the following:
1049 * - Prepare the evaluation area
1050 * - Allocate memory for the relation graph in the evaluation area
1051 * (of course, only for variable definitions) and summarize there all
1052 * variable definitions
1053 * - Allocate memory for the evaluation contexts in the evaluation area
1054 * - Recursively process all the BBs in the dominator tree (it is enough
1055 * to invoke the processing on the entry BB)
1057 * cfg: the method code
1060 mono_perform_abc_removal (MonoCompile *cfg)
1062 MonoVariableRelationsEvaluationArea area;
1065 verbose_level = cfg->verbose_level;
1067 if (TRACE_ABC_REMOVAL) {
1068 printf ("Removing array bound checks in %s\n", mono_method_full_name (cfg->method, TRUE));
1072 area.relations = (MonoSummarizedValueRelation *)
1073 alloca (sizeof (MonoSummarizedValueRelation) * (cfg->num_varinfo) * 2);
1074 area.contexts = (MonoRelationsEvaluationContext *)
1075 alloca (sizeof (MonoRelationsEvaluationContext) * (cfg->num_varinfo));
1076 for (i = 0; i < cfg->num_varinfo; i++) {
1077 area.relations [i].relation = MONO_EQ_RELATION;
1078 area.relations [i].relation_is_static_definition = TRUE;
1079 area.relations [i].next = NULL;
1080 if (cfg->vars [i]->def != NULL) {
1081 MonoInst *value = get_variable_value_from_store_instruction (cfg->vars [i]->def, i);
1082 if (value != NULL) {
1083 summarize_value (value, &(area.relations [i].related_value));
1084 if (TRACE_ABC_REMOVAL) {
1085 printf ("Summarized variable %d: ", i);
1086 print_summarized_value (&(area.relations [i].related_value));
1090 MAKE_VALUE_ANY (area.relations [i].related_value);
1091 if (TRACE_ABC_REMOVAL) {
1092 printf ("Definition of variable %d is not a proper store\n", i);
1096 MAKE_VALUE_ANY (area.relations [i].related_value);
1097 if (TRACE_ABC_REMOVAL) {
1098 printf ("Variable %d has no definition, probably it is an argument\n", i);
1102 for (i = 0; i < cfg->num_varinfo; i++) {
1103 if (area.relations [i].related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
1104 int related_index = cfg->num_varinfo + i;
1105 int related_variable = area.relations [i].related_value.value.variable.variable;
1107 area.relations [related_index].relation = MONO_EQ_RELATION;
1108 area.relations [related_index].relation_is_static_definition = TRUE;
1109 area.relations [related_index].related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
1110 area.relations [related_index].related_value.value.variable.variable = i;
1111 area.relations [related_index].related_value.value.variable.delta = - area.relations [i].related_value.value.variable.delta;
1113 area.relations [related_index].next = area.relations [related_variable].next;
1114 area.relations [related_variable].next = &(area.relations [related_index]);
1116 if (TRACE_ABC_REMOVAL) {
1117 printf ("Added symmetric summarized value for variable variable %d (to %d): ", i, related_variable);
1118 print_summarized_value (&(area.relations [related_index].related_value));
1124 process_block (cfg->bblocks [0], &area);