3 * Array bounds check removal
6 * Massimiliano Mantione (massi@ximian.com)
8 * (C) 2004 Ximian, Inc. http://www.ximian.com
14 #include <mono/metadata/debug-helpers.h>
15 #include <mono/metadata/mempool.h>
16 #include <mono/metadata/opcodes.h>
17 #include <mono/metadata/mempool-internals.h>
18 #include <mono/utils/mono-compiler.h>
24 #include "abcremoval.h"
26 #if TARGET_SIZEOF_VOID_P == 8
27 #define OP_PCONST OP_I8CONST
29 #define OP_PCONST OP_ICONST
33 #define TRACE_ABC_REMOVAL (verbose_level > 2)
34 #define REPORT_ABC_REMOVAL (verbose_level > 1)
37 * A little hack for the verbosity level.
38 * The verbosity level is stored in the cfg, but not all functions that must
39 * print something see the cfg, so we store the verbosity level here at the
40 * beginning of the algorithm.
41 * This is not thread safe (does not handle correctly different verbosity
42 * levels in different threads), and is not exact in case of dynamic changes
43 * of the verbosity level...
44 * Anyway, this is not needed, all that can happen is that something more
45 * (or less) is logged, the result is in any case correct.
47 static int verbose_level
;
50 #define RELATION_BETWEEN_VALUES(value,related_value) (\
51 ((value) > (related_value))? MONO_GT_RELATION :\
52 (((value) < (related_value))? MONO_LT_RELATION : MONO_EQ_RELATION))
54 #define MAKE_VALUE_ANY(v) do{\
55 (v).type = MONO_ANY_SUMMARIZED_VALUE;\
58 #define MAKE_VALUE_RELATION_ANY(r) do{\
59 (r)->relation = MONO_ANY_RELATION;\
60 MAKE_VALUE_ANY((r)->related_value);\
63 #define INITIALIZE_VALUE_RELATION(r) do{\
64 MAKE_VALUE_RELATION_ANY((r));\
68 #define MONO_NEGATED_RELATION(r) ((MonoValueRelation)((~(r))&MONO_ANY_RELATION))
69 #define MONO_SYMMETRIC_RELATION(r) ((MonoValueRelation)(((r)&MONO_EQ_RELATION)|(((r)&MONO_LT_RELATION)<<1)|((r&MONO_GT_RELATION)>>1)))
74 print_relation (int relation
) {
77 if (relation
& MONO_LT_RELATION
) {
81 if (relation
& MONO_EQ_RELATION
) {
88 if (relation
& MONO_GT_RELATION
) {
99 print_summarized_value (MonoSummarizedValue
*value
) {
100 switch (value
->type
) {
101 case MONO_ANY_SUMMARIZED_VALUE
:
104 case MONO_CONSTANT_SUMMARIZED_VALUE
:
105 printf ("CONSTANT %d, not-null = %d", value
->value
.constant
.value
, value
->value
.constant
.nullness
);
107 case MONO_VARIABLE_SUMMARIZED_VALUE
:
108 printf ("VARIABLE %d, delta %d, not-null = %d", value
->value
.variable
.variable
, value
->value
.variable
.delta
, value
->value
.variable
.nullness
);
110 case MONO_PHI_SUMMARIZED_VALUE
: {
113 for (phi
= 0; phi
< value
->value
.phi
.number_of_alternatives
; phi
++) {
114 if (phi
) printf (",");
115 printf ("%d", value
->value
.phi
.phi_alternatives
[phi
]);
121 g_assert_not_reached ();
126 print_summarized_value_relation (MonoSummarizedValueRelation
*relation
) {
127 printf ("Relation ");
128 print_relation (relation
->relation
);
129 printf (" with value ");
130 print_summarized_value (&(relation
->related_value
));
135 print_summarized_value_relation_chain (MonoSummarizedValueRelation
*relation
) {
136 printf ("Relations:\n");
138 print_summarized_value_relation (relation
);
140 relation
= relation
->next
;
146 print_evaluation_context_status (MonoRelationsEvaluationStatus status
) {
147 if (status
== MONO_RELATIONS_EVALUATION_NOT_STARTED
) {
148 printf ("EVALUATION_NOT_STARTED");
150 gboolean print_or
= FALSE
;
153 if (status
& MONO_RELATIONS_EVALUATION_IN_PROGRESS
) {
154 if (print_or
) printf ("|");
155 printf ("EVALUATION_IN_PROGRESS");
158 if (status
& MONO_RELATIONS_EVALUATION_COMPLETED
) {
159 if (print_or
) printf ("|");
160 printf ("EVALUATION_COMPLETED");
163 if (status
& MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING
) {
164 if (print_or
) printf ("|");
165 printf ("RECURSIVELY_ASCENDING");
168 if (status
& MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING
) {
169 if (print_or
) printf ("|");
170 printf ("RECURSIVELY_DESCENDING");
173 if (status
& MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE
) {
174 if (print_or
) printf ("|");
175 printf ("RECURSIVELY_INDEFINITE");
184 print_evaluation_context_ranges (MonoRelationsEvaluationRanges
*ranges
) {
185 printf ("(ranges: zero [%d,%d] (not-null = %d), variable [%d,%d])",
186 ranges
->zero
.lower
, ranges
->zero
.upper
, ranges
->zero
.nullness
,
187 ranges
->variable
.lower
, ranges
->variable
.upper
);
191 print_evaluation_context (MonoRelationsEvaluationContext
*context
, MonoRelationsEvaluationStatus status
) {
192 print_evaluation_context_status (status
);
193 if (status
& (MONO_RELATIONS_EVALUATION_IN_PROGRESS
|MONO_RELATIONS_EVALUATION_COMPLETED
)) {
194 print_evaluation_context_ranges (&(context
->ranges
));
201 print_evaluation_area (MonoVariableRelationsEvaluationArea
*area
) {
203 printf ("Dump of evaluation area (%d variables):\n", area
->cfg
->num_varinfo
);
204 for (i
= 0; i
< area
->cfg
->num_varinfo
; i
++) {
205 printf ("Variable %d: ", i
);
206 print_evaluation_context (&(area
->contexts
[i
]));
207 print_summarized_value_relation_chain (&(area
->relations
[i
]));
212 print_evaluation_area_contexts (MonoVariableRelationsEvaluationArea
*area
) {
214 printf ("Dump of evaluation area contexts (%d variables):\n", area
->cfg
->num_varinfo
);
215 for (i
= 0; i
< area
->cfg
->num_varinfo
; i
++) {
216 printf ("Variable %d: ", i
);
217 print_evaluation_context (&(area
->contexts
[i
]));
223 * Check if the delta of an integer variable value is safe with respect
224 * to the variable size in bytes and its kind (signed or unsigned).
225 * If the delta is not safe, make the value an "any".
227 static G_GNUC_UNUSED
void
228 check_delta_safety (MonoVariableRelationsEvaluationArea
*area
, MonoSummarizedValue
*value
) {
229 if (value
->type
== MONO_VARIABLE_SUMMARIZED_VALUE
) {
230 int variable
= value
->value
.variable
.variable
;
231 int delta
= value
->value
.variable
.delta
;
232 if ((area
->variable_value_kind
[variable
]) & MONO_UNSIGNED_VALUE_FLAG
) {
234 MAKE_VALUE_ANY (*value
);
237 if (((area
->variable_value_kind
[variable
]) & MONO_INTEGER_VALUE_SIZE_BITMASK
) < 4) {
238 MAKE_VALUE_ANY (*value
);
239 } else if (delta
> 16) {
240 MAKE_VALUE_ANY (*value
);
247 * get_relation_from_ins:
249 * Obtain relations from a MonoInst.
251 * result_value_kind: the "expected" kind of result;
252 * result: the "summarized" value
253 * returns the "actual" kind of result, if guessable (otherwise MONO_UNKNOWN_INTEGER_VALUE)
255 static MonoIntegerValueKind
256 get_relation_from_ins (MonoVariableRelationsEvaluationArea
*area
, MonoInst
*ins
, MonoSummarizedValueRelation
*result
, MonoIntegerValueKind result_value_kind
)
258 MonoIntegerValueKind value_kind
;
259 MonoSummarizedValue
*value
= &result
->related_value
;
261 if (ins
->type
== STACK_I8
) {
262 value_kind
= MONO_INTEGER_VALUE_SIZE_8
;
263 } else if (ins
->type
== STACK_I4
) {
264 value_kind
= MONO_INTEGER_VALUE_SIZE_4
;
266 value_kind
= MONO_UNKNOWN_INTEGER_VALUE
;
269 result
->relation
= MONO_EQ_RELATION
;
270 MAKE_VALUE_ANY (*value
);
272 switch (ins
->opcode
) {
274 value
->type
= MONO_CONSTANT_SUMMARIZED_VALUE
;
275 value
->value
.constant
.value
= ins
->inst_c0
;
276 value
->value
.constant
.nullness
= MONO_VALUE_MAYBE_NULL
;
279 value
->type
= MONO_VARIABLE_SUMMARIZED_VALUE
;
280 value
->value
.variable
.variable
= ins
->sreg1
;
281 value
->value
.variable
.delta
= 0;
282 value
->value
.variable
.nullness
= (MonoValueNullness
) (MONO_VALUE_IS_VARIABLE
| MONO_VALUE_MAYBE_NULL
);
285 value
->type
= MONO_VARIABLE_SUMMARIZED_VALUE
;
286 value
->value
.variable
.variable
= ins
->sreg1
;
287 value
->value
.variable
.delta
= 0;
288 value
->value
.variable
.nullness
= MONO_VALUE_MAYBE_NULL
;
289 value_kind
= MONO_INTEGER_VALUE_SIZE_8
;
292 value
->type
= MONO_PHI_SUMMARIZED_VALUE
;
293 value
->value
.phi
.number_of_alternatives
= *(ins
->inst_phi_args
);
294 value
->value
.phi
.phi_alternatives
= ins
->inst_phi_args
+ 1;
297 value
->type
= MONO_VARIABLE_SUMMARIZED_VALUE
;
298 value
->value
.variable
.variable
= ins
->sreg1
;
299 value
->value
.variable
.delta
= ins
->inst_imm
;
300 value
->value
.variable
.nullness
= MONO_VALUE_MAYBE_NULL
;
302 //check_delta_safety (area, result);
305 value
->type
= MONO_VARIABLE_SUMMARIZED_VALUE
;
306 value
->value
.variable
.variable
= ins
->sreg1
;
307 value
->value
.variable
.delta
= -ins
->inst_imm
;
308 value
->value
.variable
.nullness
= MONO_VALUE_MAYBE_NULL
;
310 //check_delta_safety (area, result);
313 /* The result of an unsigned remainder is 0 < x < the divisor */
314 result
->relation
= MONO_LT_RELATION
;
315 value
->type
= MONO_VARIABLE_SUMMARIZED_VALUE
;
316 value
->value
.variable
.variable
= ins
->sreg2
;
317 value
->value
.variable
.delta
= 0;
318 value
->value
.variable
.nullness
= MONO_VALUE_MAYBE_NULL
;
319 value_kind
= MONO_UNSIGNED_INTEGER_VALUE_SIZE_4
;
323 * We represent arrays by their length, so r1<-ldlen r2 is stored
324 * as r1 == r2 in the evaluation graph.
326 value
->type
= MONO_VARIABLE_SUMMARIZED_VALUE
;
327 value
->value
.variable
.variable
= ins
->sreg1
;
328 value
->value
.variable
.delta
= 0;
329 value
->value
.variable
.nullness
= MONO_VALUE_MAYBE_NULL
;
330 value_kind
= MONO_UNSIGNED_INTEGER_VALUE_SIZE_4
;
333 value
->type
= MONO_VARIABLE_SUMMARIZED_VALUE
;
334 value
->value
.variable
.variable
= ins
->sreg1
;
335 value
->value
.variable
.delta
= 0;
336 value
->value
.variable
.nullness
= MONO_VALUE_NOT_NULL
;
337 area
->defs
[ins
->dreg
] = ins
;
340 /* The result is non-null */
341 result
->relation
= MONO_GE_RELATION
;
342 value
->type
= MONO_CONSTANT_SUMMARIZED_VALUE
;
343 value
->value
.constant
.value
= INT_MIN
;
344 value
->value
.constant
.nullness
= MONO_VALUE_NOT_NULL
;
347 /* FIXME: Add more opcodes */
349 /* These opcodes are not currently handled while running SciMark, first
350 * column is the number of times the warning was shown:
382 * 12 outarg_vtretaddr
410 static MonoValueRelation
411 get_relation_from_branch_instruction (MonoInst
*ins
)
413 if (MONO_IS_COND_BRANCH_OP (ins
)) {
414 CompRelation rel
= mono_opcode_to_cond (ins
->opcode
);
418 return MONO_EQ_RELATION
;
420 return MONO_NE_RELATION
;
423 return MONO_LE_RELATION
;
426 return MONO_GE_RELATION
;
429 return MONO_LT_RELATION
;
432 return MONO_GT_RELATION
;
434 g_assert_not_reached ();
435 return MONO_ANY_RELATION
;
438 return MONO_ANY_RELATION
;
443 * Given a BB, find its entry condition and put its relations in a
444 * "MonoAdditionalVariableRelationsForBB" structure.
446 * relations: the resulting relations (entry condition of the given BB)
449 get_relations_from_previous_bb (MonoVariableRelationsEvaluationArea
*area
, MonoBasicBlock
*bb
, MonoAdditionalVariableRelationsForBB
*relations
)
451 MonoBasicBlock
*in_bb
;
452 MonoInst
*ins
, *compare
, *branch
;
453 MonoValueRelation branch_relation
;
454 MonoValueRelation symmetric_relation
;
457 INITIALIZE_VALUE_RELATION (&(relations
->relation1
.relation
));
458 relations
->relation1
.relation
.relation_is_static_definition
= FALSE
;
459 relations
->relation1
.relation
.next
= NULL
;
460 relations
->relation1
.insertion_point
= NULL
;
461 relations
->relation1
.variable
= -1;
462 INITIALIZE_VALUE_RELATION (&(relations
->relation2
.relation
));
463 relations
->relation2
.relation
.relation_is_static_definition
= FALSE
;
464 relations
->relation2
.relation
.next
= NULL
;
465 relations
->relation2
.insertion_point
= NULL
;
466 relations
->relation2
.variable
= -1;
468 if (bb
->in_count
== 1) { /* Should write the code to "sum" conditions... */
469 in_bb
= bb
->in_bb
[0];
471 if ((in_bb
->last_ins
== NULL
) || (in_bb
->code
== in_bb
->last_ins
))
474 for (ins
= in_bb
->code
; ins
->next
!= in_bb
->last_ins
; ins
= ins
->next
)
479 branch_relation
= get_relation_from_branch_instruction (branch
);
481 if (branch_relation
!= MONO_ANY_RELATION
) {
482 if (branch
->inst_true_bb
== bb
) {
484 } else if (branch
->inst_false_bb
== bb
) {
488 g_assert_not_reached ();
491 branch_relation
= MONO_NEGATED_RELATION (branch_relation
);
492 symmetric_relation
= MONO_SYMMETRIC_RELATION (branch_relation
);
494 /* FIXME: Other compare opcodes */
495 if (compare
->opcode
== OP_ICOMPARE
) {
496 relations
->relation1
.variable
= compare
->sreg1
;
497 relations
->relation1
.relation
.relation
= branch_relation
;
498 relations
->relation1
.relation
.related_value
.type
= MONO_VARIABLE_SUMMARIZED_VALUE
;
499 relations
->relation1
.relation
.related_value
.value
.variable
.variable
= compare
->sreg2
;
500 relations
->relation1
.relation
.related_value
.value
.variable
.delta
= 0;
501 relations
->relation1
.relation
.related_value
.value
.variable
.nullness
= MONO_VALUE_MAYBE_NULL
;
503 relations
->relation2
.variable
= compare
->sreg2
;
504 relations
->relation2
.relation
.relation
= symmetric_relation
;
505 relations
->relation2
.relation
.related_value
.type
= MONO_VARIABLE_SUMMARIZED_VALUE
;
506 relations
->relation2
.relation
.related_value
.value
.variable
.variable
= compare
->sreg1
;
507 relations
->relation2
.relation
.related_value
.value
.variable
.delta
= 0;
508 relations
->relation1
.relation
.related_value
.value
.variable
.nullness
= MONO_VALUE_MAYBE_NULL
;
509 } else if (compare
->opcode
== OP_ICOMPARE_IMM
) {
510 relations
->relation1
.variable
= compare
->sreg1
;
511 relations
->relation1
.relation
.relation
= branch_relation
;
512 relations
->relation1
.relation
.related_value
.type
= MONO_CONSTANT_SUMMARIZED_VALUE
;
513 relations
->relation1
.relation
.related_value
.value
.constant
.value
= compare
->inst_imm
;
514 relations
->relation1
.relation
.related_value
.value
.constant
.nullness
= MONO_VALUE_MAYBE_NULL
;
521 * Add the given relations to the evaluation area.
522 * area: the evaluation area
523 * change: the relations that must be added
526 apply_change_to_evaluation_area (MonoVariableRelationsEvaluationArea
*area
, MonoAdditionalVariableRelation
*change
)
528 MonoSummarizedValueRelation
*base_relation
;
530 if (change
->relation
.relation
!= MONO_ANY_RELATION
) {
531 base_relation
= &(area
->relations
[change
->variable
]);
532 while ((base_relation
->next
!= NULL
) && (base_relation
->next
->relation_is_static_definition
)) {
533 base_relation
= base_relation
->next
;
535 change
->insertion_point
= base_relation
;
536 change
->relation
.next
= base_relation
->next
;
537 base_relation
->next
= &(change
->relation
);
542 * Remove the given relation from the evaluation area.
543 * change: the relation that must be removed
546 remove_change_from_evaluation_area (MonoAdditionalVariableRelation
*change
)
548 if (change
->insertion_point
!= NULL
) {
549 change
->insertion_point
->next
= change
->relation
.next
;
550 change
->relation
.next
= NULL
;
556 clean_contexts (MonoVariableRelationsEvaluationArea
*area
, int number
)
558 memset(area
->statuses
, MONO_RELATIONS_EVALUATION_NOT_STARTED
, number
* sizeof(MonoRelationsEvaluationStatus
));
562 union_nullness (MonoRelationsEvaluationRange
*range
, MonoValueNullness n
)
564 range
->nullness
= (MonoValueNullness
) (range
->nullness
& (MONO_VALUE_NULLNESS_MASK
& n
));
568 intersect_nullness (MonoRelationsEvaluationRange
*range
, MonoValueNullness n
, MonoValueRelation relation
)
571 case MONO_NO_RELATION
:
572 case MONO_ANY_RELATION
:
573 case MONO_NE_RELATION
:
574 range
->nullness
= MONO_VALUE_MAYBE_NULL
;
577 range
->nullness
= (MonoValueNullness
) (range
->nullness
| (MONO_VALUE_NULLNESS_MASK
& n
));
582 * Perform the intersection of a range and a constant value (taking into
583 * account the relation that the value has with the range).
584 * range: the range that will be intersected with the value
585 * value: the value that will be intersected with the range
586 * relation: the relation between the range and the value
589 intersect_value( MonoRelationsEvaluationRange
*range
, MonoSummarizedConstantValue value
, MonoValueRelation relation
)
592 case MONO_NO_RELATION
:
593 MONO_MAKE_RELATIONS_EVALUATION_RANGE_IMPOSSIBLE (*range
);
595 case MONO_ANY_RELATION
:
597 case MONO_EQ_RELATION
:
598 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range
->upper
, value
.value
);
599 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range
->lower
, value
.value
);
601 case MONO_NE_RELATION
: {
602 /* IMPROVEMENT Figure this out! (ignoring it is safe anyway) */
605 case MONO_LT_RELATION
:
606 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range
->upper
, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (value
.value
));
608 case MONO_LE_RELATION
:
609 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range
->upper
, value
.value
);
611 case MONO_GT_RELATION
:
612 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range
->lower
, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (value
.value
));
614 case MONO_GE_RELATION
:
615 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range
->lower
, value
.value
);
618 g_assert_not_reached();
620 intersect_nullness (range
, value
.nullness
, relation
);
625 * Perform the intersection of two pairs of ranges (taking into account the
626 * relation between the ranges and a given delta).
627 * ranges: the ranges that will be intersected
628 * other_ranges the other ranges that will be intersected
629 * delta: the delta between the pairs of ranges
630 * relation: the relation between the pairs of ranges
633 intersect_ranges (MonoRelationsEvaluationRanges
*ranges
, MonoRelationsEvaluationRanges
*other_ranges
, MonoSummarizedVariableValue value
, MonoValueRelation relation
)
635 if (value
.delta
== 0) {
637 case MONO_NO_RELATION
:
638 MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (*ranges
);
640 case MONO_ANY_RELATION
:
642 case MONO_EQ_RELATION
:
643 MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (*ranges
, *other_ranges
);
645 case MONO_NE_RELATION
: {
646 /* FIXME Figure this out! (ignoring it is safe anyway) */
649 case MONO_LT_RELATION
:
650 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges
->zero
.upper
, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (other_ranges
->zero
.upper
));
651 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges
->variable
.upper
, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (other_ranges
->variable
.upper
));
653 case MONO_LE_RELATION
:
654 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges
->zero
.upper
, other_ranges
->zero
.upper
);
655 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges
->variable
.upper
, other_ranges
->variable
.upper
);
657 case MONO_GT_RELATION
:
658 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges
->zero
.lower
, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (other_ranges
->zero
.lower
));
659 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges
->variable
.lower
, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (other_ranges
->variable
.lower
));
661 case MONO_GE_RELATION
:
662 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges
->zero
.lower
, other_ranges
->zero
.lower
);
663 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges
->variable
.lower
, other_ranges
->variable
.lower
);
666 g_assert_not_reached();
668 if (value
.nullness
& MONO_VALUE_IS_VARIABLE
)
669 intersect_nullness (&ranges
->zero
, other_ranges
->zero
.nullness
, relation
);
670 intersect_nullness (&ranges
->zero
, value
.nullness
, relation
);
672 MonoRelationsEvaluationRanges translated_ranges
= *other_ranges
;
673 MONO_ADD_DELTA_SAFELY_TO_RANGES (translated_ranges
, value
.delta
);
674 MonoSummarizedVariableValue translated_value
= value
;
675 translated_value
.delta
= 0;
676 intersect_ranges (ranges
, &translated_ranges
, translated_value
, relation
);
681 * Recursive method that traverses the relation graph to evaluate the
682 * relation between two variables.
683 * At the end of the execution, the resulting ranges are in the context of
684 * the "starting" variable.
685 * area: the current evaluation area (it contains the relation graph and
686 * memory for all the evaluation contexts is already allocated)
687 * variable: starting variable (the value ranges in its context are the result
688 * of the execution of this procedure)
689 * target_variable: the variable with respect to which the starting variable
690 * is evaluated (tipically the starting variable is the index
691 * and the target one is the array (which means its length))
692 * father_context: the previous evaluation context in recursive invocations
693 * (or NULL for the first invocation)
696 evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea
*area
, const int variable
, const int target_variable
, MonoRelationsEvaluationContext
*father_context
)
698 MonoRelationsEvaluationContext
* const context
= &(area
->contexts
[variable
]);
699 MonoRelationsEvaluationStatus
* const status
= &(area
->statuses
[variable
]);
701 // First of all, we check the evaluation status
702 // (what must be done is *very* different in each case)
704 case MONO_RELATIONS_EVALUATION_NOT_STARTED
: {
705 MonoSummarizedValueRelation
*relation
= &(area
->relations
[variable
]);
707 if (TRACE_ABC_REMOVAL
) {
708 printf ("Evaluating variable %d (target variable %d); ", variable
, target_variable
);
709 print_summarized_value_relation (relation
);
713 // We properly inizialize the context
714 *status
= MONO_RELATIONS_EVALUATION_IN_PROGRESS
;
715 context
->father
= father_context
;
716 MONO_MAKE_RELATIONS_EVALUATION_RANGES_WEAK (context
->ranges
);
718 // If we have found the target variable, we can set the range
719 // related to it in the context to "equal" (which is [0,0])
720 if (variable
== target_variable
) {
721 if (TRACE_ABC_REMOVAL
) {
722 printf ("Target variable reached (%d), continuing to evaluate relations with constants\n", variable
);
724 context
->ranges
.variable
.lower
= 0;
725 context
->ranges
.variable
.upper
= 0;
728 // Examine all relations for this variable (scan the list)
729 // The contribute of each relation will be intersected (logical and)
730 while (relation
!= NULL
) {
731 context
->current_relation
= relation
;
733 if (TRACE_ABC_REMOVAL
) {
734 printf ("Processing (%d): ", variable
);
735 print_summarized_value_relation (relation
);
739 // We decie what to do according the the type of the related value
740 switch (relation
->related_value
.type
) {
741 case MONO_ANY_SUMMARIZED_VALUE
:
742 // No added information, skip it
744 case MONO_CONSTANT_SUMMARIZED_VALUE
:
745 // Intersect range with constant (taking into account the relation)
746 intersect_value (&(context
->ranges
.zero
), relation
->related_value
.value
.constant
, relation
->relation
);
748 case MONO_VARIABLE_SUMMARIZED_VALUE
:
749 // Generally, evaluate related variable and intersect ranges.
750 // However, some check is necessary...
752 // If the relation is "ANY", nothing to do (no added information)
753 if (relation
->relation
!= MONO_ANY_RELATION
) {
754 int related_variable
= relation
->related_value
.value
.variable
.variable
;
755 MonoRelationsEvaluationContext
*related_context
= &(area
->contexts
[related_variable
]);
756 MonoRelationsEvaluationStatus related_status
= area
->statuses
[related_variable
];
758 // The second condition in the "or" avoids messing with "back edges" in the graph traversal
759 // (they are simply ignored instead of triggering the handling of recursion)
760 if ( (related_status
== MONO_RELATIONS_EVALUATION_NOT_STARTED
) || !
761 ((related_context
->current_relation
->related_value
.type
== MONO_VARIABLE_SUMMARIZED_VALUE
) &&
762 (related_context
->current_relation
->related_value
.value
.variable
.variable
== variable
))) {
763 // Evaluate the related variable
764 evaluate_relation_with_target_variable (area
, related_variable
, target_variable
, context
);
766 // Check if we are part of a recursive loop
767 if (*status
& MONO_RELATIONS_EVALUATION_IS_RECURSIVE
) {
768 if (TRACE_ABC_REMOVAL
) {
769 printf ("Recursivity detected for variable %d (target variable %d), status ", variable
, target_variable
);
770 print_evaluation_context_status (*status
);
773 // If we are, check if the evaluation of the related variable is complete
774 if (related_status
== MONO_RELATIONS_EVALUATION_COMPLETED
) {
775 // If it is complete, we are part of a recursive definition.
776 // Since it is a *definition* (and definitions are evaluated *before*
777 // conditions because they are first in the list), intersection is not
778 // strictly necessary, we simply copy the ranges and apply the delta
779 context
->ranges
= related_context
->ranges
;
780 /* Delta has already been checked for over/under-flow when evaluating values */
781 MONO_ADD_DELTA_SAFELY_TO_RANGES (context
->ranges
, relation
->related_value
.value
.variable
.delta
);
782 *status
= MONO_RELATIONS_EVALUATION_COMPLETED
;
783 if (TRACE_ABC_REMOVAL
) {
784 printf (", ranges already computed, result: \n");
785 print_evaluation_context_ranges (&(context
->ranges
));
786 printf (" (delta is %d)\n", relation
->related_value
.value
.variable
.delta
);
789 // If it is not complete, do nothing (we do not have enough information)
790 if (TRACE_ABC_REMOVAL
) {
791 printf (", ranges not computed\n");
795 // If we are not (the common case) intersect the result
796 intersect_ranges (&(context
->ranges
), &(related_context
->ranges
), relation
->related_value
.value
.variable
, relation
->relation
);
799 if (TRACE_ABC_REMOVAL
) {
800 printf ("Relation is a back-edge in this traversal, skipping\n");
805 case MONO_PHI_SUMMARIZED_VALUE
: {
806 // We must compute all PHI alternatives, combining the results (with a union, which is a logical "or"),
807 // and intersect this result with the ranges in the context; we must also take into account recursions
808 // (with loops that can be ascending, descending, or indefinite)
809 MonoRelationsEvaluationRanges phi_ranges
;
811 gboolean is_ascending
= FALSE
;
812 gboolean is_descending
= FALSE
;
814 MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (phi_ranges
);
815 phi_ranges
.zero
.nullness
= relation
->related_value
.value
.phi
.number_of_alternatives
> 0 ? MONO_VALUE_NOT_NULL
: MONO_VALUE_MAYBE_NULL
;
816 for (phi
= 0; phi
< relation
->related_value
.value
.phi
.number_of_alternatives
; phi
++) {
817 int phi_alternative
= relation
->related_value
.value
.phi
.phi_alternatives
[phi
];
818 evaluate_relation_with_target_variable (area
, phi_alternative
, target_variable
, context
);
820 // This means we are part of a recursive loop
821 if (*status
& MONO_RELATIONS_EVALUATION_IS_RECURSIVE
) {
822 if (TRACE_ABC_REMOVAL
) {
823 printf ("Recursivity detected for variable %d (target variable %d), status ", variable
, target_variable
);
824 print_evaluation_context_status (*status
);
827 if (*status
& MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING
) {
830 if (*status
& MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING
) {
831 is_descending
= TRUE
;
833 if (*status
& MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE
) {
835 is_descending
= TRUE
;
837 phi_ranges
.zero
.nullness
= MONO_VALUE_MAYBE_NULL
;
839 // Clear "recursivity" bits in the status (recursion has been handled)
840 *status
= MONO_RELATIONS_EVALUATION_IN_PROGRESS
;
842 MONO_RELATIONS_EVALUATION_RANGES_UNION (phi_ranges
, area
->contexts
[phi_alternative
].ranges
);
843 union_nullness (&phi_ranges
.zero
, area
->contexts
[phi_alternative
].ranges
.zero
.nullness
);
847 // Apply the effects of all recursive loops
849 phi_ranges
.zero
.upper
= INT_MAX
;
850 phi_ranges
.variable
.upper
= INT_MAX
;
853 phi_ranges
.zero
.lower
= INT_MIN
;
854 phi_ranges
.variable
.lower
= INT_MIN
;
857 // Intersect final result
858 MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (context
->ranges
, phi_ranges
);
859 intersect_nullness (&context
->ranges
.zero
, phi_ranges
.zero
.nullness
, MONO_EQ_RELATION
);
863 g_assert_not_reached();
866 // Pass to next relation
867 relation
= relation
->next
;
870 // Check if any recursivity bits are still in the status, and in any case clear them
871 if (*status
& MONO_RELATIONS_EVALUATION_IS_RECURSIVE
) {
872 if (TRACE_ABC_REMOVAL
) {
873 printf ("Recursivity for variable %d (target variable %d) discards computation, status ", variable
, target_variable
);
874 print_evaluation_context_status (*status
);
877 // If yes, we did not have enough information (most likely we were evaluated inside a PHI, but we also
878 // depended on the same PHI, which was still in evaluation...), so clear the status to "NOT_STARTED"
879 // (if we will be evaluated again, the PHI will be already done, so our evaluation will succeed)
880 *status
= MONO_RELATIONS_EVALUATION_NOT_STARTED
;
882 if (TRACE_ABC_REMOVAL
) {
883 printf ("Ranges for variable %d (target variable %d) computed: ", variable
, target_variable
);
884 print_evaluation_context_ranges (&(context
->ranges
));
887 // If not (the common case) the evaluation is complete, and the result is in the context
888 *status
= MONO_RELATIONS_EVALUATION_COMPLETED
;
892 case MONO_RELATIONS_EVALUATION_IN_PROGRESS
: {
893 // This means we are in a recursive loop
894 MonoRelationsEvaluationContext
*current_context
= father_context
;
895 MonoRelationsEvaluationContext
*last_context
= context
->father
;
896 gboolean evaluation_can_be_recursive
= TRUE
;
897 gboolean evaluation_is_definition
= TRUE
;
900 if (TRACE_ABC_REMOVAL
) {
901 printf ("Evaluation of variable %d (target variable %d) already in progress\n", variable
, target_variable
);
902 print_evaluation_context (context
, *status
);
903 print_summarized_value_relation (context
->current_relation
);
907 // We must check if the loop can be a recursive definition (we scan the whole loop)
908 while (current_context
!= last_context
) {
909 if (current_context
== NULL
) {
910 printf ("Broken recursive ring in ABC removal\n");
911 g_assert_not_reached ();
914 if (current_context
->current_relation
->relation_is_static_definition
) {
915 if (current_context
->current_relation
->related_value
.type
== MONO_VARIABLE_SUMMARIZED_VALUE
) {
916 /* No need to check path_value for over/under-flow, since delta should be safe */
917 path_value
+= current_context
->current_relation
->related_value
.value
.variable
.delta
;
918 } else if (current_context
->current_relation
->related_value
.type
!= MONO_PHI_SUMMARIZED_VALUE
) {
919 evaluation_can_be_recursive
= FALSE
;
922 evaluation_is_definition
= FALSE
;
923 evaluation_can_be_recursive
= FALSE
;
926 current_context
= current_context
->father
;
929 // If this is a recursive definition, we properly flag the status in all the involved contexts
930 if (evaluation_is_definition
) {
931 MonoRelationsEvaluationStatus recursive_status
;
932 if (evaluation_can_be_recursive
) {
933 if (path_value
> 0) {
934 recursive_status
= MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING
;
935 } else if (path_value
< 0) {
936 recursive_status
= MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING
;
938 recursive_status
= MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE
;
941 recursive_status
= MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE
;
944 if (TRACE_ABC_REMOVAL
) {
945 printf ("Recursivity accepted (");
946 print_evaluation_context_status (recursive_status
);
950 current_context
= father_context
;
951 while (current_context
!= last_context
) {
952 int index
= current_context
- area
->contexts
;
953 MonoRelationsEvaluationStatus
*current_status
= &(area
->statuses
[index
]);
954 *current_status
= (MonoRelationsEvaluationStatus
)(*current_status
| recursive_status
);
955 current_context
= current_context
->father
;
958 if (TRACE_ABC_REMOVAL
) {
959 printf ("Recursivity rejected (some relation in the cycle is not a defintion)\n");
964 case MONO_RELATIONS_EVALUATION_COMPLETED
: {
968 if (TRACE_ABC_REMOVAL
) {
969 printf ("Variable %d (target variable %d) already in a recursive ring, skipping\n", variable
, target_variable
);
970 print_evaluation_context (context
, *status
);
971 print_summarized_value_relation (context
->current_relation
);
980 * Apply the given value kind to the given range
983 apply_value_kind_to_range (MonoRelationsEvaluationRange
*range
, MonoIntegerValueKind value_kind
)
985 if (value_kind
!= MONO_UNKNOWN_INTEGER_VALUE
) {
986 if (value_kind
& MONO_UNSIGNED_VALUE_FLAG
) {
987 if (range
->lower
< 0) {
990 if ((value_kind
& MONO_INTEGER_VALUE_SIZE_BITMASK
) == 1) {
991 if (range
->upper
> 0xff) {
994 } else if ((value_kind
& MONO_INTEGER_VALUE_SIZE_BITMASK
) == 2) {
995 if (range
->upper
> 0xffff) {
996 range
->upper
= 0xffff;
1000 if ((value_kind
& MONO_INTEGER_VALUE_SIZE_BITMASK
) == 1) {
1001 if (range
->lower
< -0x80) {
1002 range
->lower
= -0x80;
1004 if (range
->upper
> 0x7f) {
1005 range
->upper
= 0x7f;
1007 } else if ((value_kind
& MONO_INTEGER_VALUE_SIZE_BITMASK
) == 2) {
1008 if (range
->lower
< -0x8000) {
1009 range
->lower
= -0x8000;
1011 if (range
->upper
> 0x7fff) {
1012 range
->upper
= 0x7fff;
1020 * Attempt the removal of bounds checks from a MonoInst.
1021 * inst: the MonoInst
1022 * area: the current evaluation area (it contains the relation graph and
1023 * memory for all the evaluation contexts is already allocated)
1026 remove_abc_from_inst (MonoInst
*ins
, MonoVariableRelationsEvaluationArea
*area
)
1028 /* FIXME: Add support for 'constant' arrays and constant indexes */
1030 int array_variable
= ins
->sreg1
;
1031 int index_variable
= ins
->sreg2
;
1032 MonoRelationsEvaluationContext
*array_context
= &(area
->contexts
[array_variable
]);
1033 MonoRelationsEvaluationContext
*index_context
= &(area
->contexts
[index_variable
]);
1035 clean_contexts (area
, area
->cfg
->next_vreg
);
1037 evaluate_relation_with_target_variable (area
, index_variable
, array_variable
, NULL
);
1038 evaluate_relation_with_target_variable (area
, array_variable
, array_variable
, NULL
);
1040 if ((index_context
->ranges
.zero
.lower
>=0) && ((index_context
->ranges
.variable
.upper
< 0)||(index_context
->ranges
.zero
.upper
< array_context
->ranges
.zero
.lower
))) {
1041 if (REPORT_ABC_REMOVAL
) {
1042 printf ("ARRAY-ACCESS: removed bounds check on array %d with index %d\n",
1043 array_variable
, index_variable
);
1047 if (TRACE_ABC_REMOVAL
) {
1048 if (index_context
->ranges
.zero
.lower
>= 0) {
1049 printf ("ARRAY-ACCESS: Removed lower bound check on array %d with index %d\n", array_variable
, index_variable
);
1051 if (index_context
->ranges
.variable
.upper
< 0) {
1052 printf ("ARRAY-ACCESS: Removed upper bound check (through variable) on array %d with index %d\n", array_variable
, index_variable
);
1054 if (index_context
->ranges
.zero
.upper
< array_context
->ranges
.zero
.lower
) {
1055 printf ("ARRAY-ACCESS: Removed upper bound check (through constant) on array %d with index %d\n", array_variable
, index_variable
);
1062 eval_non_null (MonoVariableRelationsEvaluationArea
*area
, int reg
)
1064 MonoRelationsEvaluationContext
*context
= &(area
->contexts
[reg
]);
1066 clean_contexts (area
, area
->cfg
->next_vreg
);
1067 evaluate_relation_with_target_variable (area
, reg
, reg
, NULL
);
1069 return context
->ranges
.zero
.nullness
== MONO_VALUE_NOT_NULL
;
1073 add_non_null (MonoVariableRelationsEvaluationArea
*area
, MonoCompile
*cfg
, int reg
,
1074 GSList
**check_relations
)
1076 MonoAdditionalVariableRelation
*rel
;
1078 rel
= (MonoAdditionalVariableRelation
*)mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoAdditionalVariableRelation
));
1079 rel
->variable
= reg
;
1080 rel
->relation
.relation
= MONO_GE_RELATION
;
1081 rel
->relation
.related_value
.type
= MONO_CONSTANT_SUMMARIZED_VALUE
;
1082 rel
->relation
.related_value
.value
.constant
.value
= INT_MIN
;
1083 rel
->relation
.related_value
.value
.constant
.nullness
= MONO_VALUE_NOT_NULL
;
1085 apply_change_to_evaluation_area (area
, rel
);
1087 *check_relations
= g_slist_append_mempool (cfg
->mempool
, *check_relations
, rel
);
1091 * Process a BB removing bounds checks from array accesses.
1092 * It does the following (in sequence):
1093 * - Get the BB entry condition
1094 * - Add its relations to the relation graph in the evaluation area
1095 * - Process all the MonoInst trees in the BB
1096 * - Recursively process all the children BBs in the dominator tree
1097 * - Remove the relations previously added to the relation graph
1099 * bb: the BB that must be processed
1100 * area: the current evaluation area (it contains the relation graph and
1101 * memory for all the evaluation contexts is already allocated)
1104 process_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoVariableRelationsEvaluationArea
*area
) {
1106 MonoAdditionalVariableRelationsForBB additional_relations
;
1107 GSList
*dominated_bb
, *l
;
1108 GSList
*check_relations
= NULL
;
1110 if (TRACE_ABC_REMOVAL
) {
1111 printf ("\nABCREM BLOCK/2 %d [dfn %d]...\n", bb
->block_num
, bb
->dfn
);
1114 if (bb
->region
!= -1)
1117 get_relations_from_previous_bb (area
, bb
, &additional_relations
);
1118 if (TRACE_ABC_REMOVAL
) {
1119 if (additional_relations
.relation1
.relation
.relation
!= MONO_ANY_RELATION
) {
1120 printf ("Adding relation 1 on variable %d: ", additional_relations
.relation1
.variable
);
1121 print_summarized_value_relation (&(additional_relations
.relation1
.relation
));
1124 if (additional_relations
.relation2
.relation
.relation
!= MONO_ANY_RELATION
) {
1125 printf ("Adding relation 2 on variable %d: ", additional_relations
.relation2
.variable
);
1126 print_summarized_value_relation (&(additional_relations
.relation2
.relation
));
1130 apply_change_to_evaluation_area (area
, &(additional_relations
.relation1
));
1131 apply_change_to_evaluation_area (area
, &(additional_relations
.relation2
));
1133 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1134 MonoAdditionalVariableRelation
*rel
;
1135 int array_var
, index_var
;
1137 if (TRACE_ABC_REMOVAL
)
1138 mono_print_ins (ins
);
1140 if (ins
->opcode
== OP_BOUNDS_CHECK
) { /* Handle OP_LDELEMA2D, too */
1141 array_var
= ins
->sreg1
;
1142 index_var
= ins
->sreg2
;
1144 remove_abc_from_inst (ins
, area
);
1146 /* We can derive additional relations from the bounds check */
1147 if (ins
->opcode
!= OP_NOP
) {
1148 rel
= (MonoAdditionalVariableRelation
*)mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoAdditionalVariableRelation
));
1149 rel
->variable
= index_var
;
1150 rel
->relation
.relation
= MONO_LT_RELATION
;
1151 rel
->relation
.related_value
.type
= MONO_VARIABLE_SUMMARIZED_VALUE
;
1152 rel
->relation
.related_value
.value
.variable
.variable
= array_var
;
1153 rel
->relation
.related_value
.value
.variable
.delta
= 0;
1154 rel
->relation
.related_value
.value
.variable
.nullness
= MONO_VALUE_MAYBE_NULL
;
1156 apply_change_to_evaluation_area (area
, rel
);
1158 check_relations
= g_slist_append_mempool (cfg
->mempool
, check_relations
, rel
);
1160 rel
= (MonoAdditionalVariableRelation
*)mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoAdditionalVariableRelation
));
1161 rel
->variable
= index_var
;
1162 rel
->relation
.relation
= MONO_GE_RELATION
;
1163 rel
->relation
.related_value
.type
= MONO_CONSTANT_SUMMARIZED_VALUE
;
1164 rel
->relation
.related_value
.value
.constant
.value
= 0;
1165 rel
->relation
.related_value
.value
.constant
.nullness
= MONO_VALUE_MAYBE_NULL
;
1167 apply_change_to_evaluation_area (area
, rel
);
1169 check_relations
= g_slist_append_mempool (cfg
->mempool
, check_relations
, rel
);
1173 if (ins
->opcode
== OP_CHECK_THIS
) {
1174 if (eval_non_null (area
, ins
->sreg1
)) {
1175 if (REPORT_ABC_REMOVAL
)
1176 printf ("ARRAY-ACCESS: removed check_this instruction for R%d.\n", ins
->sreg1
);
1181 if (ins
->opcode
== OP_NOT_NULL
)
1182 add_non_null (area
, cfg
, ins
->sreg1
, &check_relations
);
1184 if (ins
->opcode
== OP_COMPARE_IMM
&& ins
->inst_imm
== 0 && ins
->next
&& ins
->next
->opcode
== OP_COND_EXC_EQ
) {
1185 if (eval_non_null (area
, ins
->sreg1
)) {
1186 if (REPORT_ABC_REMOVAL
)
1187 printf ("ARRAY-ACCESS: Removed null check for R%d.\n", ins
->sreg1
);
1188 NULLIFY_INS (ins
->next
);
1194 * Eliminate MONO_INST_FAULT flags if possible.
1196 if (COMPILE_LLVM (cfg
) && (ins
->opcode
== OP_LDLEN
||
1197 ins
->opcode
== OP_BOUNDS_CHECK
||
1198 ins
->opcode
== OP_STRLEN
||
1199 (MONO_IS_LOAD_MEMBASE (ins
) && (ins
->flags
& MONO_INST_FAULT
)) ||
1200 (MONO_IS_STORE_MEMBASE (ins
) && (ins
->flags
& MONO_INST_FAULT
)))) {
1203 if (MONO_IS_STORE_MEMBASE (ins
))
1204 reg
= ins
->inst_destbasereg
;
1205 else if (MONO_IS_LOAD_MEMBASE (ins
))
1206 reg
= ins
->inst_basereg
;
1211 * This doesn't work because LLVM can move the non-faulting loads before the faulting
1212 * ones (test_0_llvm_moving_faulting_loads ()).
1213 * So only do it if we know the load cannot be moved before the instruction which ensures it is not
1214 * null (i.e. the def of its sreg).
1216 if (area
->defs
[reg
] && area
->defs
[reg
]->opcode
== OP_NEWARR
) {
1217 if (REPORT_ABC_REMOVAL
)
1218 printf ("ARRAY-ACCESS: removed MONO_INST_FAULT flag.\n");
1219 ins
->flags
&= ~MONO_INST_FAULT
;
1222 if (eval_non_null (area, reg)) {
1223 if (REPORT_ABC_REMOVAL)
1224 printf ("ARRAY-ACCESS: removed MONO_INST_FAULT flag.\n");
1225 ins->flags &= ~MONO_INST_FAULT;
1227 add_non_null (area, cfg, reg, &check_relations);
1233 for (dominated_bb
= bb
->dominated
; dominated_bb
!= NULL
; dominated_bb
= dominated_bb
->next
) {
1234 process_block (cfg
, (MonoBasicBlock
*) (dominated_bb
->data
), area
);
1237 for (l
= check_relations
; l
; l
= l
->next
)
1238 remove_change_from_evaluation_area ((MonoAdditionalVariableRelation
*)l
->data
);
1240 remove_change_from_evaluation_area (&(additional_relations
.relation1
));
1241 remove_change_from_evaluation_area (&(additional_relations
.relation2
));
1244 static MonoIntegerValueKind
1245 type_to_value_kind (MonoType
*type
)
1248 return MONO_UNKNOWN_INTEGER_VALUE
;
1249 switch (type
->type
) {
1251 return MONO_INTEGER_VALUE_SIZE_1
;
1254 return MONO_UNSIGNED_INTEGER_VALUE_SIZE_1
;
1257 return MONO_INTEGER_VALUE_SIZE_2
;
1260 return MONO_UNSIGNED_INTEGER_VALUE_SIZE_2
;
1263 return MONO_INTEGER_VALUE_SIZE_4
;
1266 return MONO_UNSIGNED_INTEGER_VALUE_SIZE_4
;
1269 return (MonoIntegerValueKind
)TARGET_SIZEOF_VOID_P
;
1272 return (MonoIntegerValueKind
)(MONO_UNSIGNED_VALUE_FLAG
| TARGET_SIZEOF_VOID_P
);
1275 return MONO_INTEGER_VALUE_SIZE_8
;
1278 return MONO_UNSIGNED_INTEGER_VALUE_SIZE_8
;
1280 return MONO_UNKNOWN_INTEGER_VALUE
;
1285 * mono_perform_abc_removal:
1286 * \param cfg Control Flow Graph
1288 * Performs the ABC removal from a cfg in SSA form.
1289 * It does the following:
1290 * - Prepare the evaluation area
1291 * - Allocate memory for the relation graph in the evaluation area
1292 * (of course, only for variable definitions) and summarize there all
1293 * variable definitions
1294 * - Allocate memory for the evaluation contexts in the evaluation area
1295 * - Recursively process all the BBs in the dominator tree (it is enough
1296 * to invoke the processing on the entry BB)
1298 * cfg: the method code
1301 mono_perform_abc_removal (MonoCompile
*cfg
)
1303 MonoVariableRelationsEvaluationArea area
;
1307 verbose_level
= cfg
->verbose_level
;
1310 area
.relations
= (MonoSummarizedValueRelation
*)
1311 mono_mempool_alloc (cfg
->mempool
, sizeof (MonoSummarizedValueRelation
) * (cfg
->next_vreg
) * 2);
1313 area
.contexts
= (MonoRelationsEvaluationContext
*)
1314 mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoRelationsEvaluationContext
) * (cfg
->next_vreg
));
1316 area
.statuses
= (MonoRelationsEvaluationStatus
*)
1317 mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoRelationsEvaluationStatus
) * (cfg
->next_vreg
));
1319 area
.variable_value_kind
= (MonoIntegerValueKind
*)
1320 mono_mempool_alloc (cfg
->mempool
, sizeof (MonoIntegerValueKind
) * (cfg
->next_vreg
));
1321 area
.defs
= (MonoInst
**)mono_mempool_alloc (cfg
->mempool
, sizeof (MonoInst
*) * cfg
->next_vreg
);
1322 for (i
= 0; i
< cfg
->next_vreg
; i
++) {
1323 area
.variable_value_kind
[i
] = MONO_UNKNOWN_INTEGER_VALUE
;
1324 area
.relations
[i
].relation
= MONO_EQ_RELATION
;
1325 area
.relations
[i
].relation_is_static_definition
= TRUE
;
1326 MAKE_VALUE_ANY (area
.relations
[i
].related_value
);
1327 area
.relations
[i
].next
= NULL
;
1328 area
.defs
[i
] = NULL
;
1331 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1334 if (TRACE_ABC_REMOVAL
)
1335 printf ("\nABCREM BLOCK %d:\n", bb
->block_num
);
1337 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1338 const char *spec
= INS_INFO (ins
->opcode
);
1341 if (spec
[MONO_INST_DEST
] == ' ' || MONO_IS_STORE_MEMBASE (ins
))
1344 MONO_INS_FOR_EACH_REG (ins
, idx
, reg
) {
1345 MonoInst
*var
= get_vreg_to_inst (cfg
, *reg
);
1346 if (var
&& (var
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
)))
1349 if (idx
< MONO_INST_LEN
) {
1350 if (TRACE_ABC_REMOVAL
)
1351 printf ("Global register %d is not in the SSA form, skipping.\n", *reg
);
1355 if (spec
[MONO_INST_DEST
] == 'i') {
1356 MonoIntegerValueKind effective_value_kind
;
1357 MonoRelationsEvaluationRange range
;
1358 MonoSummarizedValueRelation
*type_relation
;
1361 if (TRACE_ABC_REMOVAL
)
1362 mono_print_ins (ins
);
1364 var
= get_vreg_to_inst (cfg
, ins
->dreg
);
1366 area
.variable_value_kind
[ins
->dreg
] = type_to_value_kind (var
->inst_vtype
);
1368 effective_value_kind
= get_relation_from_ins (&area
, ins
, &area
.relations
[ins
->dreg
], area
.variable_value_kind
[ins
->dreg
]);
1370 MONO_MAKE_RELATIONS_EVALUATION_RANGE_WEAK (range
);
1371 apply_value_kind_to_range (&range
, area
.variable_value_kind
[ins
->dreg
]);
1372 apply_value_kind_to_range (&range
, effective_value_kind
);
1374 if (range
.upper
< INT_MAX
) {
1375 type_relation
= (MonoSummarizedValueRelation
*) mono_mempool_alloc (cfg
->mempool
, sizeof (MonoSummarizedValueRelation
));
1376 type_relation
->relation
= MONO_LE_RELATION
;
1377 type_relation
->related_value
.type
= MONO_CONSTANT_SUMMARIZED_VALUE
;
1378 type_relation
->related_value
.value
.constant
.value
= range
.upper
;
1379 type_relation
->relation_is_static_definition
= TRUE
;
1380 type_relation
->next
= area
.relations
[ins
->dreg
].next
;
1381 area
.relations
[ins
->dreg
].next
= type_relation
;
1382 if (TRACE_ABC_REMOVAL
) {
1383 printf ("[var%d <= %d]", ins
->dreg
, range
.upper
);
1386 if (range
.lower
> INT_MIN
) {
1387 type_relation
= (MonoSummarizedValueRelation
*) mono_mempool_alloc (cfg
->mempool
, sizeof (MonoSummarizedValueRelation
));
1388 type_relation
->relation
= MONO_GE_RELATION
;
1389 type_relation
->related_value
.type
= MONO_CONSTANT_SUMMARIZED_VALUE
;
1390 type_relation
->related_value
.value
.constant
.value
= range
.lower
;
1391 type_relation
->relation_is_static_definition
= TRUE
;
1392 type_relation
->next
= area
.relations
[ins
->dreg
].next
;
1393 area
.relations
[ins
->dreg
].next
= type_relation
;
1394 if (TRACE_ABC_REMOVAL
) {
1395 printf ("[var%d >= %d]", ins
->dreg
, range
.lower
);
1398 if (TRACE_ABC_REMOVAL
) {
1399 printf ("Summarized variable %d: ", ins
->dreg
);
1400 print_summarized_value (&(area
.relations
[ins
->dreg
].related_value
));
1407 /* Add symmetric relations */
1408 for (i
= 0; i
< cfg
->next_vreg
; i
++) {
1409 if (area
.relations
[i
].related_value
.type
== MONO_VARIABLE_SUMMARIZED_VALUE
) {
1410 int related_index
= cfg
->next_vreg
+ i
;
1411 int related_variable
= area
.relations
[i
].related_value
.value
.variable
.variable
;
1412 MonoValueNullness symmetric_nullness
= MONO_VALUE_MAYBE_NULL
;
1413 if (area
.relations
[i
].related_value
.value
.variable
.nullness
& MONO_VALUE_IS_VARIABLE
) {
1414 symmetric_nullness
= area
.relations
[i
].related_value
.value
.variable
.nullness
;
1417 area
.relations
[related_index
].relation
= MONO_EQ_RELATION
;
1418 area
.relations
[related_index
].relation_is_static_definition
= TRUE
;
1419 area
.relations
[related_index
].related_value
.type
= MONO_VARIABLE_SUMMARIZED_VALUE
;
1420 area
.relations
[related_index
].related_value
.value
.variable
.variable
= i
;
1421 area
.relations
[related_index
].related_value
.value
.variable
.delta
= - area
.relations
[i
].related_value
.value
.variable
.delta
;
1422 area
.relations
[related_index
].related_value
.value
.variable
.nullness
= symmetric_nullness
;
1424 area
.relations
[related_index
].next
= area
.relations
[related_variable
].next
;
1425 area
.relations
[related_variable
].next
= &(area
.relations
[related_index
]);
1427 if (TRACE_ABC_REMOVAL
) {
1428 printf ("Added symmetric summarized value for variable variable %d (to %d): ", i
, related_variable
);
1429 print_summarized_value (&(area
.relations
[related_index
].related_value
));
1435 process_block (cfg
, cfg
->bblocks
[0], &area
);
1438 #else /* !DISABLE_JIT */
1440 MONO_EMPTY_SOURCE_FILE (abcremoval
);
1442 #endif /* !DISABLE_JIT */