17a8e84d91a9da461fd4b40e08d5040b4d624d1e
[mono.git] / mono / mini / abcremoval.c
1 /*
2  * abcremoval.c: Array bounds check removal
3  *
4  * Author:
5  *   Massimiliano Mantione (massi@ximian.com)
6  *
7  * (C) 2004 Ximian, Inc.  http://www.ximian.com
8  */
9 #include <string.h>
10 #include <stdio.h>
11
12 #include <mono/metadata/debug-helpers.h>
13 #include <mono/metadata/mempool.h>
14 #include <mono/metadata/opcodes.h>
15 #include <mono/metadata/mempool-internals.h>
16
17 #include <config.h>
18
19 #ifndef DISABLE_JIT
20
21 #include "abcremoval.h"
22
23 #if SIZEOF_VOID_P == 8
24 #define OP_PCONST OP_I8CONST
25 #else
26 #define OP_PCONST OP_ICONST
27 #endif
28
29
30 #define TRACE_ABC_REMOVAL (verbose_level > 2)
31 #define REPORT_ABC_REMOVAL (verbose_level > 1)
32
33 /*
34  * A little hack for the verbosity level.
35  * The verbosity level is stored in the cfg, but not all functions that must
36  * print something see the cfg, so we store the verbosity level here at the
37  * beginning of the algorithm.
38  * This is not thread safe (does not handle correctly different verbosity
39  * levels in different threads), and is not exact in case of dynamic changes
40  * of the verbosity level...
41  * Anyway, this is not needed, all that can happen is that something more
42  * (or less) is logged, the result is in any case correct.
43  */
44 static int verbose_level;
45
46
47 #define RELATION_BETWEEN_VALUES(value,related_value) (\
48         ((value) > (related_value))? MONO_GT_RELATION :\
49         (((value) < (related_value))? MONO_LT_RELATION : MONO_EQ_RELATION))
50
51 #define MAKE_VALUE_ANY(v) do{\
52                 (v).type = MONO_ANY_SUMMARIZED_VALUE;\
53         } while (0)
54
55 #define MAKE_VALUE_RELATION_ANY(r) do{\
56                 (r)->relation = MONO_ANY_RELATION;\
57                 MAKE_VALUE_ANY((r)->related_value);\
58         } while (0)
59
60 #define INITIALIZE_VALUE_RELATION(r) do{\
61                 MAKE_VALUE_RELATION_ANY((r));\
62                 (r)->next = NULL;\
63         } while (0)
64
65 #define MONO_NEGATED_RELATION(r) ((MonoValueRelation)((~(r))&MONO_ANY_RELATION))
66 #define MONO_SYMMETRIC_RELATION(r) ((MonoValueRelation)(((r)&MONO_EQ_RELATION)|(((r)&MONO_LT_RELATION)<<1)|((r&MONO_GT_RELATION)>>1)))
67
68
69
70 static void
71 print_relation (int relation) {
72         int print_or = 0;
73         printf ("(");
74         if (relation & MONO_LT_RELATION) {
75                 printf ("LT");
76                 print_or = 1;
77         }
78         if (relation & MONO_EQ_RELATION) {
79                 if (print_or) {
80                         printf ("|");
81                 }
82                 printf ("EQ");
83                 print_or = 1;
84         }
85         if (relation & MONO_GT_RELATION) {
86                 if (print_or) {
87                         printf ("|");
88                 }
89                 printf ("GT");
90                 print_or = 1;
91         }
92         printf (")");
93 }
94
95 static void
96 print_summarized_value (MonoSummarizedValue *value) {
97         switch (value->type) {
98         case MONO_ANY_SUMMARIZED_VALUE:
99                 printf ("ANY");
100                 break;
101         case MONO_CONSTANT_SUMMARIZED_VALUE:
102                 printf ("CONSTANT %d", value->value.constant.value);
103                 break;
104         case MONO_VARIABLE_SUMMARIZED_VALUE:
105                 printf ("VARIABLE %d, delta %d", value->value.variable.variable, value->value.variable.delta);
106                 break;
107         case MONO_PHI_SUMMARIZED_VALUE: {
108                 int phi;
109                 printf ("PHI (");
110                 for (phi = 0; phi < value->value.phi.number_of_alternatives; phi++) {
111                         if (phi) printf (",");
112                         printf ("%d", value->value.phi.phi_alternatives [phi]);
113                 }
114                 printf (")");
115                 break;
116         }
117         default:
118                 g_assert_not_reached ();
119         }
120 }
121
122 static void
123 print_summarized_value_relation (MonoSummarizedValueRelation *relation) {
124         printf ("Relation ");
125         print_relation (relation->relation);
126         printf (" with value ");
127         print_summarized_value (&(relation->related_value));
128 }
129
130 #if 0
131 static void
132 print_summarized_value_relation_chain (MonoSummarizedValueRelation *relation) {
133         printf ("Relations:\n");
134         while (relation) {
135                 print_summarized_value_relation (relation);
136                 printf ("\n");
137                 relation = relation->next;
138         }
139 }
140 #endif
141
142 static void
143 print_evaluation_context_status (MonoRelationsEvaluationStatus status) {
144         if (status == MONO_RELATIONS_EVALUATION_NOT_STARTED) {
145                 printf ("EVALUATION_NOT_STARTED");
146         } else {
147                 gboolean print_or = FALSE;
148                 
149                 printf ("(");
150                 if (status & MONO_RELATIONS_EVALUATION_IN_PROGRESS) {
151                         if (print_or) printf ("|");
152                         printf ("EVALUATION_IN_PROGRESS");
153                         print_or = TRUE;
154                 }
155                 if (status & MONO_RELATIONS_EVALUATION_COMPLETED) {
156                         if (print_or) printf ("|");
157                         printf ("EVALUATION_COMPLETED");
158                         print_or = TRUE;
159                 }
160                 if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING) {
161                         if (print_or) printf ("|");
162                         printf ("RECURSIVELY_ASCENDING");
163                         print_or = TRUE;
164                 }
165                 if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING) {
166                         if (print_or) printf ("|");
167                         printf ("RECURSIVELY_DESCENDING");
168                         print_or = TRUE;
169                 }
170                 if (status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE) {
171                         if (print_or) printf ("|");
172                         printf ("RECURSIVELY_INDEFINITE");
173                         print_or = TRUE;
174                 }
175                 printf (")");
176         }
177 }
178
179
180 static void
181 print_evaluation_context_ranges (MonoRelationsEvaluationRanges *ranges) {
182         printf ("(ranges: zero [%d,%d], variable [%d,%d])", ranges->zero.lower, ranges->zero.upper, ranges->variable.lower, ranges->variable.upper);
183 }
184
185 static void
186 print_evaluation_context (MonoRelationsEvaluationContext *context, MonoRelationsEvaluationStatus status) {
187         print_evaluation_context_status (status);
188         if (status & (MONO_RELATIONS_EVALUATION_IN_PROGRESS|MONO_RELATIONS_EVALUATION_COMPLETED)) {
189                 print_evaluation_context_ranges (&(context->ranges));
190         }
191         printf ("\n");
192 }
193
194 #if 0
195 static void
196 print_evaluation_area (MonoVariableRelationsEvaluationArea *area) {
197         int i;
198         printf ("Dump of evaluation area (%d variables):\n", area->cfg->num_varinfo);
199         for (i = 0; i < area->cfg->num_varinfo; i++) {
200                 printf ("Variable %d: ", i);
201                 print_evaluation_context (&(area->contexts [i]));
202                 print_summarized_value_relation_chain (&(area->relations [i]));
203         }
204 }
205
206 static void
207 print_evaluation_area_contexts (MonoVariableRelationsEvaluationArea *area) {
208         int i;
209         printf ("Dump of evaluation area contexts (%d variables):\n", area->cfg->num_varinfo);
210         for (i = 0; i < area->cfg->num_varinfo; i++) {
211                 printf ("Variable %d: ", i);
212                 print_evaluation_context (&(area->contexts [i]));
213         }
214 }
215 #endif
216
217 /*
218  * Check if the delta of an integer variable value is safe with respect
219  * to the variable size in bytes and its kind (signed or unsigned).
220  * If the delta is not safe, make the value an "any".
221  */
222 static G_GNUC_UNUSED void
223 check_delta_safety (MonoVariableRelationsEvaluationArea *area, MonoSummarizedValue *value) {
224         if (value->type == MONO_VARIABLE_SUMMARIZED_VALUE) {
225                 int variable = value->value.variable.variable;
226                 int delta = value->value.variable.delta;
227                 if ((area->variable_value_kind [variable]) & MONO_UNSIGNED_VALUE_FLAG) {
228                         if (delta < 0) {
229                                 MAKE_VALUE_ANY (*value);
230                         }
231                 } else {
232                         if (((area->variable_value_kind [variable]) & MONO_INTEGER_VALUE_SIZE_BITMASK) < 4) {
233                                 MAKE_VALUE_ANY (*value);
234                         } else if (delta > 16) {
235                                 MAKE_VALUE_ANY (*value);
236                         }
237                 }
238         }
239 }
240
241 /*
242  * get_relation_from_ins:
243  *
244  *   Obtain relations from a MonoInst.
245  *
246  * result_value_kind: the "expected" kind of result;
247  * result: the "summarized" value
248  * returns the "actual" kind of result, if guessable (otherwise MONO_UNKNOWN_INTEGER_VALUE)
249  */
250 static MonoIntegerValueKind
251 get_relation_from_ins (MonoVariableRelationsEvaluationArea *area, MonoInst *ins, MonoSummarizedValueRelation *result, MonoIntegerValueKind result_value_kind)
252 {
253         MonoIntegerValueKind value_kind;
254         MonoSummarizedValue *value = &result->related_value;
255         
256         if (ins->type == STACK_I8) {
257                 value_kind = MONO_INTEGER_VALUE_SIZE_8;
258         } else if (ins->type == STACK_I4) {
259                 value_kind = MONO_INTEGER_VALUE_SIZE_4;
260         } else {
261                 value_kind = MONO_UNKNOWN_INTEGER_VALUE;
262         }
263
264         result->relation = MONO_EQ_RELATION;
265         MAKE_VALUE_ANY (*value);
266
267         switch (ins->opcode) {
268         case OP_ICONST:
269                 value->type = MONO_CONSTANT_SUMMARIZED_VALUE;
270                 value->value.constant.value = ins->inst_c0;
271                 break;
272         case OP_MOVE:
273                 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
274                 value->value.variable.variable = ins->sreg1;
275                 value->value.variable.delta = 0;
276                 break;
277         case OP_SEXT_I4:
278                 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
279                 value->value.variable.variable = ins->sreg1;
280                 value->value.variable.delta = 0;
281                 value_kind = MONO_INTEGER_VALUE_SIZE_8;
282                 break;
283         case OP_PHI:
284                 value->type = MONO_PHI_SUMMARIZED_VALUE;
285                 value->value.phi.number_of_alternatives = *(ins->inst_phi_args);
286                 value->value.phi.phi_alternatives = ins->inst_phi_args + 1;
287                 break;
288         case OP_IADD_IMM:
289                 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
290                 value->value.variable.variable = ins->sreg1;
291                 value->value.variable.delta = ins->inst_imm;
292                 /* FIXME: */
293                 //check_delta_safety (area, result);
294                 break;
295         case OP_ISUB_IMM:
296                 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
297                 value->value.variable.variable = ins->sreg1;
298                 value->value.variable.delta = -ins->inst_imm;
299                 /* FIXME: */
300                 //check_delta_safety (area, result);
301                 break;
302         case OP_IREM_UN:
303                 /* The result of an unsigned remainder is 0 < x < the divisor */
304                 result->relation = MONO_LT_RELATION;
305                 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
306                 value->value.variable.variable = ins->sreg2;
307                 value->value.variable.delta = 0;
308                 value_kind = MONO_UNSIGNED_INTEGER_VALUE_SIZE_4;
309                 break;
310         case OP_LDLEN:
311                 /*
312                  * We represent arrays by their length, so r1<-ldlen r2 is stored
313                  * as r1 == r2 in the evaluation graph.
314                  */
315                 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
316                 value->value.variable.variable = ins->sreg1;
317                 value->value.variable.delta = 0;
318                 value_kind = MONO_UNSIGNED_INTEGER_VALUE_SIZE_4;
319                 break;
320         case OP_NEWARR:
321                 value->type = MONO_VARIABLE_SUMMARIZED_VALUE;
322                 value->value.variable.variable = ins->sreg1;
323                 value->value.variable.delta = 0;
324                 area->defs [ins->dreg] = ins;
325                 break;
326         case OP_LDADDR:
327                 /* The result is non-null */
328                 result->relation = MONO_GT_RELATION;
329                 value->type = MONO_CONSTANT_SUMMARIZED_VALUE;
330                 value->value.constant.value = 0;
331                 break;
332
333                 /* FIXME: Add more opcodes */
334         default:
335                 /* These opcodes are not currently handled while running SciMark, first
336                  * column is the number of times the warning was shown:
337                  *
338                  *       1 add_imm
339                  *       1 float_conv_to_i8
340                  *       1 int_mul_ovf_un
341                  *       1 int_neg
342                  *       1 int_or
343                  *       1 int_shr_un
344                  *       1 localloc
345                  *       1 long_ceq
346                  *       1 long_rem
347                  *       1 long_sub
348                  *       2 int_ceq
349                  *       2 int_conv_to_i2
350                  *       2 int_min
351                  *       2 lcall
352                  *       2 long_div
353                  *       3 int_conv_to_u2
354                  *       3 long_shr_imm
355                  *       4 int_rem
356                  *       4 int_rem_imm
357                  *       4 loadi1_membase
358                  *       4 loadu4_membase
359                  *       5 int_div
360                  *       5 shl_imm
361                  *       6 int_div_imm
362                  *       6 int_mul
363                  *       9 int_mul_imm
364                  *       9 zext_i4
365                  *      10 int_shr_imm
366                  *      12 int_shr_un_imm
367                  *      12 long_add_imm
368                  *      12 outarg_vtretaddr
369                  *      12 strlen
370                  *      13 int_or_imm
371                  *      23 call_membase
372                  *      23 int_conv_to_u1
373                  *      23 long_add
374                  *      24 int_and_imm
375                  *      24 int_shl_imm
376                  *      24 loadu2_membase
377                  *      29 loadi8_membase
378                  *      31 llvm_outarg_vt
379                  *      34 int_sub
380                  *      34 loadu1_membase
381                  *      42 int_add
382                  *      85 ldaddr
383                  *     116 loadi4_membase
384                  *     159 x86_lea
385                  *     179 sext_i4
386                  *     291 load_membase
387                  *     462 i8const
388                  *     472 call
389                  */
390                 
391                 break;
392         }
393         return value_kind;
394 }
395
396 static MonoValueRelation
397 get_relation_from_branch_instruction (MonoInst *ins)
398 {
399         if (MONO_IS_COND_BRANCH_OP (ins)) {
400                 CompRelation rel = mono_opcode_to_cond (ins->opcode);
401
402                 switch (rel) {
403                 case CMP_EQ:
404                         return MONO_EQ_RELATION;
405                 case CMP_NE:
406                         return MONO_NE_RELATION;
407                 case CMP_LE:
408                 case CMP_LE_UN:
409                         return MONO_LE_RELATION;
410                 case CMP_GE:
411                 case CMP_GE_UN:
412                         return MONO_GE_RELATION;
413                 case CMP_LT:
414                 case CMP_LT_UN:
415                         return MONO_LT_RELATION;
416                 case CMP_GT:
417                 case CMP_GT_UN:
418                         return MONO_GT_RELATION;
419                 default:
420                         g_assert_not_reached ();
421                         return MONO_ANY_RELATION;
422                 }
423         } else {
424                 return MONO_ANY_RELATION;
425         }
426 }
427
428 /*
429  * Given a BB, find its entry condition and put its relations in a
430  * "MonoAdditionalVariableRelationsForBB" structure.
431  * bb: the BB
432  * relations: the resulting relations (entry condition of the given BB)
433  */
434 static void
435 get_relations_from_previous_bb (MonoVariableRelationsEvaluationArea *area, MonoBasicBlock *bb, MonoAdditionalVariableRelationsForBB *relations)
436 {
437         MonoBasicBlock *in_bb;
438         MonoInst *ins, *compare, *branch;
439         MonoValueRelation branch_relation;
440         MonoValueRelation symmetric_relation;
441         gboolean code_path;
442         
443         INITIALIZE_VALUE_RELATION (&(relations->relation1.relation));
444         relations->relation1.relation.relation_is_static_definition = FALSE;
445         relations->relation1.relation.next = NULL;
446         relations->relation1.insertion_point = NULL;
447         relations->relation1.variable = -1;
448         INITIALIZE_VALUE_RELATION (&(relations->relation2.relation));
449         relations->relation2.relation.relation_is_static_definition = FALSE;
450         relations->relation2.relation.next = NULL;      
451         relations->relation2.insertion_point = NULL;
452         relations->relation2.variable = -1;
453         
454         if (bb->in_count == 1) { /* Should write the code to "sum" conditions... */
455                 in_bb = bb->in_bb [0];
456
457                 if ((in_bb->last_ins == NULL) || (in_bb->code == in_bb->last_ins))
458                         return;
459
460                 for (ins = in_bb->code; ins->next != in_bb->last_ins; ins = ins->next)
461                         ;
462
463                 compare = ins;
464                 branch = ins->next;
465                 branch_relation = get_relation_from_branch_instruction (branch);
466
467                 if (branch_relation != MONO_ANY_RELATION) {
468                         if (branch->inst_true_bb == bb) {
469                                 code_path = TRUE;
470                         } else if (branch->inst_false_bb == bb) {
471                                 code_path = FALSE;
472                         } else {
473                                 code_path = TRUE;
474                                 g_assert_not_reached ();
475                         }
476                         if (!code_path)
477                                 branch_relation = MONO_NEGATED_RELATION (branch_relation);
478                         symmetric_relation = MONO_SYMMETRIC_RELATION (branch_relation);
479
480                         /* FIXME: Other compare opcodes */
481                         if (compare->opcode == OP_ICOMPARE) {
482                                 relations->relation1.variable = compare->sreg1;
483                                 relations->relation1.relation.relation = branch_relation;
484                                 relations->relation1.relation.related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
485                                 relations->relation1.relation.related_value.value.variable.variable = compare->sreg2;
486                                 relations->relation1.relation.related_value.value.variable.delta = 0;
487
488                                 relations->relation2.variable = compare->sreg2;
489                                 relations->relation2.relation.relation = symmetric_relation;
490                                 relations->relation2.relation.related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
491                                 relations->relation2.relation.related_value.value.variable.variable = compare->sreg1;
492                                 relations->relation2.relation.related_value.value.variable.delta = 0;
493                         } else if (compare->opcode == OP_ICOMPARE_IMM) {
494                                 relations->relation1.variable = compare->sreg1;
495                                 relations->relation1.relation.relation = branch_relation;
496                                 relations->relation1.relation.related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
497                                 relations->relation1.relation.related_value.value.constant.value = compare->inst_imm;
498                         }
499                 }
500         }
501 }
502
503 /*
504  * Add the given relations to the evaluation area.
505  * area: the evaluation area
506  * change: the relations that must be added
507  */
508 static void
509 apply_change_to_evaluation_area (MonoVariableRelationsEvaluationArea *area, MonoAdditionalVariableRelation *change)
510 {
511         MonoSummarizedValueRelation *base_relation;
512         
513         if (change->relation.relation != MONO_ANY_RELATION) {
514                 base_relation = &(area->relations [change->variable]);
515                 while ((base_relation->next != NULL) && (base_relation->next->relation_is_static_definition)) {
516                         base_relation = base_relation->next;
517                 }
518                 change->insertion_point = base_relation;
519                 change->relation.next = base_relation->next;
520                 base_relation->next = &(change->relation);
521         }
522 }
523
524 /*
525  * Remove the given relation from the evaluation area.
526  * change: the relation that must be removed
527  */
528 static void
529 remove_change_from_evaluation_area (MonoAdditionalVariableRelation *change)
530 {
531         if (change->insertion_point != NULL) {
532                 change->insertion_point->next = change->relation.next;
533                 change->relation.next = NULL;
534         }
535 }
536
537
538 static void
539 clean_contexts (MonoVariableRelationsEvaluationArea *area, int number)
540 {
541         memset(area->statuses, MONO_RELATIONS_EVALUATION_NOT_STARTED, number * sizeof(MonoRelationsEvaluationStatus));
542 }
543
544
545 /*
546  * Perform the intersection of a range and a constant value (taking into
547  * account the relation that the value has with the range).
548  * range: the range that will be intersected with the value
549  * value: the value that will be intersected with the range
550  * relation: the relation between the range and the value
551  */
552 static void
553 intersect_value( MonoRelationsEvaluationRange *range, int value, MonoValueRelation relation )
554 {
555         switch (relation) {
556         case MONO_NO_RELATION:
557                 MONO_MAKE_RELATIONS_EVALUATION_RANGE_IMPOSSIBLE (*range);
558                 break;
559         case MONO_ANY_RELATION:
560                 break;
561         case MONO_EQ_RELATION:
562                 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, value);
563                 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, value);
564                 break;
565         case MONO_NE_RELATION: {
566                 /* IMPROVEMENT Figure this out! (ignoring it is safe anyway) */
567                 break;
568         }
569         case MONO_LT_RELATION:
570                 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (value));
571                 break;
572         case MONO_LE_RELATION:
573                 MONO_UPPER_EVALUATION_RANGE_INTERSECTION (range->upper, value);
574                 break;
575         case MONO_GT_RELATION:
576                 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (value));
577                 break;
578         case MONO_GE_RELATION:
579                 MONO_LOWER_EVALUATION_RANGE_INTERSECTION (range->lower, value);
580                 break;
581         default:
582                 g_assert_not_reached();
583         }
584 }
585
586
587 /*
588  * Perform the intersection of two pairs of ranges (taking into account the
589  * relation between the ranges and a given delta).
590  * ranges: the ranges that will be intersected
591  * other_ranges the other ranges that will be intersected
592  * delta: the delta between the pairs of ranges
593  * relation: the relation between the pairs of ranges
594  */
595 static void
596 intersect_ranges( MonoRelationsEvaluationRanges *ranges, MonoRelationsEvaluationRanges *other_ranges, int delta, MonoValueRelation relation )
597 {
598         if (delta == 0) {
599                 switch (relation) {
600                 case MONO_NO_RELATION:
601                         MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (*ranges);
602                         break;
603                 case MONO_ANY_RELATION:
604                         break;
605                 case MONO_EQ_RELATION:
606                         MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (*ranges, *other_ranges);
607                         break;
608                 case MONO_NE_RELATION: {
609                         /* FIXME Figure this out! (ignoring it is safe anyway) */
610                         break;
611                 }
612                 case MONO_LT_RELATION:
613                         MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->zero.upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->zero.upper));
614                         MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->variable.upper, MONO_UPPER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->variable.upper));
615                         break;
616                 case MONO_LE_RELATION:
617                         MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->zero.upper, other_ranges->zero.upper);
618                         MONO_UPPER_EVALUATION_RANGE_INTERSECTION (ranges->variable.upper, other_ranges->variable.upper);
619                         break;
620                 case MONO_GT_RELATION:
621                         MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->zero.lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->zero.lower));
622                         MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->variable.lower, MONO_LOWER_EVALUATION_RANGE_NOT_EQUAL (other_ranges->variable.lower));
623                         break;
624                 case MONO_GE_RELATION:
625                         MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->zero.lower, other_ranges->zero.lower);
626                         MONO_LOWER_EVALUATION_RANGE_INTERSECTION (ranges->variable.lower, other_ranges->variable.lower);
627                         break;
628                 default:
629                         g_assert_not_reached();
630                 }
631         } else {
632                 MonoRelationsEvaluationRanges translated_ranges = *other_ranges;
633                 MONO_ADD_DELTA_SAFELY_TO_RANGES (translated_ranges, delta);
634                 intersect_ranges( ranges, &translated_ranges, FALSE, relation );
635         }
636 }
637
638 /*
639  * Recursive method that traverses the relation graph to evaluate the
640  * relation between two variables.
641  * At the end of the execution, the resulting ranges are in the context of
642  * the "starting" variable.
643  * area: the current evaluation area (it contains the relation graph and
644  *       memory for all the evaluation contexts is already allocated)
645  * variable: starting variable (the value ranges in its context are the result
646  *           of the execution of this procedure)
647  * target_variable: the variable with respect to which the starting variable
648  *                  is evaluated (tipically the starting variable is the index
649  *                  and the target one is the array (which means its length))
650  * father_context: the previous evaluation context in recursive invocations
651  *                 (or NULL for the first invocation)
652  */
653 static void
654 evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *area, const int variable, const int target_variable, MonoRelationsEvaluationContext *father_context)
655 {
656         MonoRelationsEvaluationContext * const context = &(area->contexts [variable]);
657         MonoRelationsEvaluationStatus * const status = &(area->statuses [variable]);
658         
659         // First of all, we check the evaluation status
660         // (what must be done is *very* different in each case)
661         switch (*status) {
662         case MONO_RELATIONS_EVALUATION_NOT_STARTED: {
663                 MonoSummarizedValueRelation *relation = &(area->relations [variable]);
664                 
665                 if (TRACE_ABC_REMOVAL) {
666                         printf ("Evaluating variable %d (target variable %d)\n", variable, target_variable);
667                         print_summarized_value_relation (relation);
668                         printf ("\n");
669                 }
670                 
671                 // We properly inizialize the context
672                 *status = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
673                 context->father = father_context;
674                 MONO_MAKE_RELATIONS_EVALUATION_RANGES_WEAK (context->ranges);
675                 
676                 // If we have found the target variable, we can set the range
677                 // related to it in the context to "equal" (which is [0,0])
678                 if (variable == target_variable) {
679                         if (TRACE_ABC_REMOVAL) {
680                                 printf ("Target variable reached (%d), continuing to evaluate relations with constants\n", variable);
681                         }
682                         context->ranges.variable.lower = 0;
683                         context->ranges.variable.upper = 0;
684                 }
685                 
686                 // Examine all relations for this variable (scan the list)
687                 // The contribute of each relation will be intersected (logical and)
688                 while (relation != NULL) {
689                         context->current_relation = relation;
690                         
691                         if (TRACE_ABC_REMOVAL) {
692                                 printf ("Processing (%d): ", variable);
693                                 print_summarized_value_relation (relation);
694                                 printf ("\n");
695                         }
696                         
697                         // We decie what to do according the the type of the related value
698                         switch (relation->related_value.type) {
699                         case MONO_ANY_SUMMARIZED_VALUE:
700                                 // No added information, skip it
701                                 break;
702                         case MONO_CONSTANT_SUMMARIZED_VALUE:
703                                 // Intersect range with constant (taking into account the relation)
704                                 intersect_value (&(context->ranges.zero), relation->related_value.value.constant.value, relation->relation);
705                                 break;
706                         case MONO_VARIABLE_SUMMARIZED_VALUE:
707                                 // Generally, evaluate related variable and intersect ranges.
708                                 // However, some check is necessary...
709                                 
710                                 // If the relation is "ANY", nothing to do (no added information)
711                                 if (relation->relation != MONO_ANY_RELATION) {
712                                         int related_variable = relation->related_value.value.variable.variable;
713                                         MonoRelationsEvaluationContext *related_context = &(area->contexts [related_variable]);
714                                         MonoRelationsEvaluationStatus related_status = area->statuses [related_variable];
715                                         
716                                         // The second condition in the "or" avoids messing with "back edges" in the graph traversal
717                                         // (they are simply ignored instead of triggering the handling of recursion)
718                                         if ( (related_status == MONO_RELATIONS_EVALUATION_NOT_STARTED) || !
719                                                         ((related_context->current_relation->related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) &&
720                                                         (related_context->current_relation->related_value.value.variable.variable == variable))) {
721                                                 // Evaluate the related variable
722                                                 evaluate_relation_with_target_variable (area, related_variable, target_variable, context);
723                                                 
724                                                 // Check if we are part of a recursive loop
725                                                 if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
726                                                         if (TRACE_ABC_REMOVAL) {
727                                                                 printf ("Recursivity detected for variable %d (target variable %d), status ", variable, target_variable);
728                                                                 print_evaluation_context_status (*status);
729                                                         }
730                                                         
731                                                         // If we are, check if the evaluation of the related variable is complete
732                                                         if (related_status == MONO_RELATIONS_EVALUATION_COMPLETED) {
733                                                                 // If it is complete, we are part of a recursive definition.
734                                                                 // Since it is a *definition* (and definitions are evaluated *before*
735                                                                 // conditions because they are first in the list), intersection is not
736                                                                 // strictly necessary, we simply copy the ranges and apply the delta
737                                                                 context->ranges = related_context->ranges;
738                                                                 /* Delta has already been checked for over/under-flow when evaluating values */
739                                                                 MONO_ADD_DELTA_SAFELY_TO_RANGES (context->ranges, relation->related_value.value.variable.delta);
740                                                                 *status = MONO_RELATIONS_EVALUATION_COMPLETED;
741                                                                 if (TRACE_ABC_REMOVAL) {
742                                                                         printf (", ranges already computed, result: \n");
743                                                                         print_evaluation_context_ranges (&(context->ranges));
744                                                                         printf (" (delta is %d)\n", relation->related_value.value.variable.delta);
745                                                                 }
746                                                         } else {
747                                                                 // If it is not complete, do nothing (we do not have enough information)
748                                                                 if (TRACE_ABC_REMOVAL) {
749                                                                         printf (", ranges not computed\n");
750                                                                 }
751                                                         }
752                                                 } else {
753                                                         // If we are not (the common case) intersect the result
754                                                         intersect_ranges( &(context->ranges), &(related_context->ranges), relation->related_value.value.variable.delta, relation->relation );
755                                                 }
756                                         } else {
757                                                 if (TRACE_ABC_REMOVAL) {
758                                                         printf ("Relation is a back-edge in this traversal, skipping\n");
759                                                 }
760                                         }
761                                 }
762                                 break;
763                         case MONO_PHI_SUMMARIZED_VALUE: {
764                                 // We must compute all PHI alternatives, combining the results (with a union, which is a logical "or"),
765                                 // and intersect this result with the ranges in the context; we must also take into account recursions
766                                 // (with loops that can be ascending, descending, or indefinite)
767                                 MonoRelationsEvaluationRanges phi_ranges;
768                                 int phi;
769                                 gboolean is_ascending = FALSE;
770                                 gboolean is_descending = FALSE;
771                                 
772                                 MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (phi_ranges);
773                                 for (phi = 0; phi < relation->related_value.value.phi.number_of_alternatives; phi++) {
774                                         int phi_alternative = relation->related_value.value.phi.phi_alternatives [phi];
775                                         evaluate_relation_with_target_variable (area, phi_alternative, target_variable, context);
776                                         
777                                         // This means we are part of a recursive loop
778                                         if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
779                                                 if (TRACE_ABC_REMOVAL) {
780                                                         printf ("Recursivity detected for variable %d (target variable %d), status ", variable, target_variable);
781                                                         print_evaluation_context_status (*status);
782                                                         printf ("\n");
783                                                 }
784                                                 if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING) {
785                                                         is_ascending = TRUE;
786                                                 }
787                                                 if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING) {
788                                                         is_descending = TRUE;
789                                                 }
790                                                 if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE) {
791                                                         is_ascending = TRUE;
792                                                         is_descending = TRUE;
793                                                 }
794                                                 
795                                                 // Clear "recursivity" bits in the status (recursion has been handled)
796                                                 *status = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
797                                         } else {
798                                                 MONO_RELATIONS_EVALUATION_RANGES_UNION (phi_ranges, area->contexts [phi_alternative].ranges);
799                                         }
800                                 }
801                                 
802                                 // Apply the effects of all recursive loops
803                                 if (is_ascending) {
804                                         phi_ranges.zero.upper = INT_MAX;
805                                         phi_ranges.variable.upper = INT_MAX;
806                                 }
807                                 if (is_descending) {
808                                         phi_ranges.zero.lower = INT_MIN;
809                                         phi_ranges.variable.lower = INT_MIN;
810                                 }
811                                 
812                                 // Intersect final result
813                                 MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (context->ranges, phi_ranges);
814                                 break;
815                         }
816                         default:
817                                 g_assert_not_reached();
818                         }
819                         
820                         // Pass to next relation
821                         relation = relation->next;
822                 }
823                 
824                 // Check if any recursivity bits are still in the status, and in any case clear them
825                 if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) {
826                         if (TRACE_ABC_REMOVAL) {
827                                 printf ("Recursivity for variable %d (target variable %d) discards computation, status ", variable, target_variable);
828                                 print_evaluation_context_status (*status);
829                                 printf ("\n");
830                         }
831                         // If yes, we did not have enough information (most likely we were evaluated inside a PHI, but we also
832                         // depended on the same PHI, which was still in evaluation...), so clear the status to "NOT_STARTED"
833                         // (if we will be evaluated again, the PHI will be already done, so our evaluation will succeed)
834                         *status = MONO_RELATIONS_EVALUATION_NOT_STARTED;
835                 } else {
836                         if (TRACE_ABC_REMOVAL) {
837                                 printf ("Ranges for variable %d (target variable %d) computed: ", variable, target_variable);
838                                 print_evaluation_context_ranges (&(context->ranges));
839                                 printf ("\n");
840                         }
841                         // If not (the common case) the evaluation is complete, and the result is in the context
842                         *status = MONO_RELATIONS_EVALUATION_COMPLETED;
843                 }
844                 break;
845         }
846         case MONO_RELATIONS_EVALUATION_IN_PROGRESS: {
847                 // This means we are in a recursive loop
848                 MonoRelationsEvaluationContext *current_context = father_context;
849                 MonoRelationsEvaluationContext *last_context = context->father;
850                 gboolean evaluation_can_be_recursive = TRUE;
851                 gboolean evaluation_is_definition = TRUE;
852                 int path_value = 0;
853                 
854                 if (TRACE_ABC_REMOVAL) {
855                         printf ("Evaluation of variable %d (target variable %d) already in progress\n", variable, target_variable);
856                         print_evaluation_context (context, *status);
857                         print_summarized_value_relation (context->current_relation);
858                         printf ("\n");
859                 }
860                 
861                 // We must check if the loop can be a recursive definition (we scan the whole loop)
862                 while (current_context != last_context) {
863                         if (current_context == NULL) {
864                                 printf ("Broken recursive ring in ABC removal\n");
865                                 g_assert_not_reached ();
866                         }
867                         
868                         if (current_context->current_relation->relation_is_static_definition) {
869                                 if (current_context->current_relation->related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
870                                         /* No need to check path_value for over/under-flow, since delta should be safe */
871                                         path_value += current_context->current_relation->related_value.value.variable.delta;
872                                 } else if (current_context->current_relation->related_value.type != MONO_PHI_SUMMARIZED_VALUE) {
873                                         evaluation_can_be_recursive = FALSE;
874                                 }
875                         } else {
876                                 evaluation_is_definition = FALSE;
877                                 evaluation_can_be_recursive = FALSE;
878                         }
879                         
880                         current_context = current_context->father;
881                 }
882                 
883                 // If this is a recursive definition, we properly flag the status in all the involved contexts
884                 if (evaluation_is_definition) {
885                         MonoRelationsEvaluationStatus recursive_status;
886                         if (evaluation_can_be_recursive) {
887                                 if (path_value > 0) {
888                                         recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_ASCENDING;
889                                 } else if (path_value < 0) {
890                                         recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_DESCENDING;
891                                 } else {
892                                         recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE;
893                                 }
894                         } else {
895                                 recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE;
896                         }
897                         
898                         if (TRACE_ABC_REMOVAL) {
899                                 printf ("Recursivity accepted (");
900                                 print_evaluation_context_status (recursive_status);
901                                 printf (")\n");
902                         }
903                         
904                         current_context = father_context;
905                         while (current_context != last_context) {
906                                 int index = father_context - area->contexts;
907                                 MonoRelationsEvaluationStatus *current_status = &(area->statuses [index]);
908                                 *current_status = (MonoRelationsEvaluationStatus)(*current_status | recursive_status);
909                                 current_context = current_context->father;
910                         }
911                 } else {
912                         if (TRACE_ABC_REMOVAL) {
913                                 printf ("Recursivity rejected (some relation in the cycle is not a defintion)\n");
914                         }
915                 }
916                 break;
917         }
918         case MONO_RELATIONS_EVALUATION_COMPLETED: {
919                 return;
920         }
921         default:
922                 if (TRACE_ABC_REMOVAL) {
923                         printf ("Variable %d (target variable %d) already in a recursive ring, skipping\n", variable, target_variable);
924                         print_evaluation_context (context, *status);
925                         print_summarized_value_relation (context->current_relation);
926                         printf ("\n");
927                 }
928                 break;
929         }
930         
931 }
932
933 /*
934  * Apply the given value kind to the given range
935  */
936 static void
937 apply_value_kind_to_range (MonoRelationsEvaluationRange *range, MonoIntegerValueKind value_kind)
938 {
939         if (value_kind != MONO_UNKNOWN_INTEGER_VALUE) {
940                 if (value_kind & MONO_UNSIGNED_VALUE_FLAG) {
941                         if (range->lower < 0) {
942                                 range->lower = 0;
943                         }
944                         if ((value_kind & MONO_INTEGER_VALUE_SIZE_BITMASK) == 1) {
945                                 if (range->upper > 0xff) {
946                                         range->upper = 0xff;
947                                 }
948                         } else if ((value_kind & MONO_INTEGER_VALUE_SIZE_BITMASK) == 2) {
949                                 if (range->upper > 0xffff) {
950                                         range->upper = 0xffff;
951                                 }
952                         }
953                 } else {
954                         if ((value_kind & MONO_INTEGER_VALUE_SIZE_BITMASK) == 1) {
955                                 if (range->lower < -0x80) {
956                                         range->lower = -0x80;
957                                 }
958                                 if (range->upper > 0x7f) {
959                                         range->upper = 0x7f;
960                                 }
961                         } else if ((value_kind & MONO_INTEGER_VALUE_SIZE_BITMASK) == 2) {
962                                 if (range->lower < -0x8000) {
963                                         range->lower = -0x8000;
964                                 }
965                                 if (range->upper > 0x7fff) {
966                                         range->upper = 0x7fff;
967                                 }
968                         }
969                 }
970         }
971 }
972
973 /*
974  * Attempt the removal of bounds checks from a MonoInst.
975  * inst: the MonoInst
976  * area: the current evaluation area (it contains the relation graph and
977  *       memory for all the evaluation contexts is already allocated)
978  */
979 static void
980 remove_abc_from_inst (MonoInst *ins, MonoVariableRelationsEvaluationArea *area)
981 {
982         /* FIXME: Add support for 'constant' arrays and constant indexes */
983
984         int array_variable = ins->sreg1;
985         int index_variable = ins->sreg2;
986         MonoRelationsEvaluationContext *array_context = &(area->contexts [array_variable]);
987         MonoRelationsEvaluationContext *index_context = &(area->contexts [index_variable]);
988                                 
989         clean_contexts (area, area->cfg->next_vreg);
990                                 
991         evaluate_relation_with_target_variable (area, index_variable, array_variable, NULL);
992         evaluate_relation_with_target_variable (area, array_variable, array_variable, NULL);
993
994         if ((index_context->ranges.zero.lower >=0) && ((index_context->ranges.variable.upper < 0)||(index_context->ranges.zero.upper < array_context->ranges.zero.lower))) {
995                 if (REPORT_ABC_REMOVAL) {
996                         printf ("ARRAY-ACCESS: removed bounds check on array %d with index %d\n",
997                                         array_variable, index_variable);
998                 }
999                 NULLIFY_INS (ins);
1000         } else {
1001                 if (TRACE_ABC_REMOVAL) {
1002                         if (index_context->ranges.zero.lower >= 0) {
1003                                 printf ("ARRAY-ACCESS: Removed lower bound check on array %d with index %d\n", array_variable, index_variable);
1004                         }
1005                         if (index_context->ranges.variable.upper < 0) {
1006                                 printf ("ARRAY-ACCESS: Removed upper bound check (through variable) on array %d with index %d\n", array_variable, index_variable);
1007                         }
1008                         if (index_context->ranges.zero.upper < array_context->ranges.zero.lower) {
1009                                 printf ("ARRAY-ACCESS: Removed upper bound check (through constant) on array %d with index %d\n", array_variable, index_variable);
1010                         }
1011                 }
1012         }
1013 }
1014
1015 static gboolean
1016 eval_non_null (MonoVariableRelationsEvaluationArea *area, int reg)
1017 {
1018         MonoRelationsEvaluationContext *context = &(area->contexts [reg]);
1019
1020         clean_contexts (area, area->cfg->next_vreg);
1021         evaluate_relation_with_target_variable (area, reg, reg, NULL);
1022                                 
1023         return context->ranges.zero.lower > 0;
1024 }
1025
1026 static void
1027 add_non_null (MonoVariableRelationsEvaluationArea *area, MonoCompile *cfg, int reg,
1028                           GSList **check_relations)
1029 {
1030         MonoAdditionalVariableRelation *rel;
1031
1032         rel = (MonoAdditionalVariableRelation *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoAdditionalVariableRelation));
1033         rel->variable = reg;
1034         rel->relation.relation = MONO_GT_RELATION;
1035         rel->relation.related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
1036         rel->relation.related_value.value.constant.value = 0;
1037
1038         apply_change_to_evaluation_area (area, rel);
1039
1040         *check_relations = g_slist_append_mempool (cfg->mempool, *check_relations, rel);
1041 }
1042
1043 /*
1044  * Process a BB removing bounds checks from array accesses.
1045  * It does the following (in sequence):
1046  * - Get the BB entry condition
1047  * - Add its relations to the relation graph in the evaluation area
1048  * - Process all the MonoInst trees in the BB
1049  * - Recursively process all the children BBs in the dominator tree
1050  * - Remove the relations previously added to the relation graph
1051  *
1052  * bb: the BB that must be processed
1053  * area: the current evaluation area (it contains the relation graph and
1054  *       memory for all the evaluation contexts is already allocated)
1055  */
1056 static void
1057 process_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoVariableRelationsEvaluationArea *area) {
1058         int inst_index;
1059         MonoInst *ins;
1060         MonoAdditionalVariableRelationsForBB additional_relations;
1061         GSList *dominated_bb, *l;
1062         GSList *check_relations = NULL;
1063         
1064         if (TRACE_ABC_REMOVAL) {
1065                 printf ("\nProcessing block %d [dfn %d]...\n", bb->block_num, bb->dfn);
1066         }
1067
1068         if (bb->region != -1)
1069                 return;
1070
1071         get_relations_from_previous_bb (area, bb, &additional_relations);
1072         if (TRACE_ABC_REMOVAL) {
1073                 if (additional_relations.relation1.relation.relation != MONO_ANY_RELATION) {
1074                         printf ("Adding relation 1 on variable %d: ", additional_relations.relation1.variable);
1075                         print_summarized_value_relation (&(additional_relations.relation1.relation));
1076                         printf ("\n");
1077                 }
1078                 if (additional_relations.relation2.relation.relation != MONO_ANY_RELATION) {
1079                         printf ("Adding relation 2 on variable %d: ", additional_relations.relation2.variable);
1080                         print_summarized_value_relation (&(additional_relations.relation2.relation));
1081                         printf ("\n");
1082                 }
1083         }
1084         apply_change_to_evaluation_area (area, &(additional_relations.relation1));
1085         apply_change_to_evaluation_area (area, &(additional_relations.relation2));
1086
1087         inst_index = 0;
1088         for (ins = bb->code; ins; ins = ins->next) {
1089                 MonoAdditionalVariableRelation *rel;
1090                 int array_var, index_var;
1091
1092                 if (TRACE_ABC_REMOVAL) {
1093                         printf ("Processing instruction %d\n", inst_index);
1094                         inst_index++;
1095                 }
1096
1097                 if (ins->opcode == OP_BOUNDS_CHECK) { /* Handle OP_LDELEMA2D, too */
1098                         if (TRACE_ABC_REMOVAL) {
1099                                 printf ("Attempting check removal...\n");
1100                         }
1101
1102                         array_var = ins->sreg1;
1103                         index_var = ins->sreg2;
1104                 
1105                         remove_abc_from_inst (ins, area);
1106
1107                         /* We can derive additional relations from the bounds check */
1108                         if (ins->opcode != OP_NOP) {
1109                                 rel = (MonoAdditionalVariableRelation *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoAdditionalVariableRelation));
1110                                 rel->variable = index_var;
1111                                 rel->relation.relation = MONO_LT_RELATION;
1112                                 rel->relation.related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
1113                                 rel->relation.related_value.value.variable.variable = array_var;
1114                                 rel->relation.related_value.value.variable.delta = 0;
1115
1116                                 apply_change_to_evaluation_area (area, rel);
1117
1118                                 check_relations = g_slist_append_mempool (cfg->mempool, check_relations, rel);
1119
1120                                 rel = (MonoAdditionalVariableRelation *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoAdditionalVariableRelation));
1121                                 rel->variable = index_var;
1122                                 rel->relation.relation = MONO_GE_RELATION;
1123                                 rel->relation.related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
1124                                 rel->relation.related_value.value.constant.value = 0;
1125
1126                                 apply_change_to_evaluation_area (area, rel);
1127
1128                                 check_relations = g_slist_append_mempool (cfg->mempool, check_relations, rel);
1129                         }
1130                 }
1131
1132                 if (ins->opcode == OP_CHECK_THIS) {
1133                         if (eval_non_null (area, ins->sreg1)) {
1134                                 if (REPORT_ABC_REMOVAL)
1135                                         printf ("ARRAY-ACCESS: removed check_this instruction.\n");
1136                                 NULLIFY_INS (ins);
1137                         }
1138                 }
1139
1140                 if (ins->opcode == OP_NOT_NULL)
1141                         add_non_null (area, cfg, ins->sreg1, &check_relations);
1142
1143                 /* 
1144                  * FIXME: abcrem equates an array with its length,
1145                  * so a = new int [100] implies a != null, but a = new int [0] doesn't.
1146                  */
1147                 /*
1148                  * Eliminate MONO_INST_FAULT flags if possible.
1149                  */
1150                 if (COMPILE_LLVM (cfg) && (ins->opcode == OP_LDLEN ||
1151                                                                    ins->opcode == OP_BOUNDS_CHECK ||
1152                                                                    ins->opcode == OP_STRLEN ||
1153                                                                    (MONO_IS_LOAD_MEMBASE (ins) && (ins->flags & MONO_INST_FAULT)) ||
1154                                                                    (MONO_IS_STORE_MEMBASE (ins) && (ins->flags & MONO_INST_FAULT)))) {
1155                         int reg;
1156
1157                         if (MONO_IS_STORE_MEMBASE (ins))
1158                                 reg = ins->inst_destbasereg;
1159                         else if (MONO_IS_LOAD_MEMBASE (ins))
1160                                 reg = ins->inst_basereg;
1161                         else
1162                                 reg = ins->sreg1;
1163
1164                         /*
1165                          * This doesn't work because LLVM can move the non-faulting loads before the faulting
1166                          * ones (test_0_llvm_moving_faulting_loads ()).
1167                          * So only do it if we know the load cannot be moved before the instruction which ensures it is not
1168                          * null (i.e. the def of its sreg).
1169                          */
1170                         if (area->defs [reg] && area->defs [reg]->opcode == OP_NEWARR) {
1171                                 if (REPORT_ABC_REMOVAL)
1172                                         printf ("ARRAY-ACCESS: removed MONO_INST_FAULT flag.\n");
1173                                 ins->flags &= ~MONO_INST_FAULT;
1174                         }
1175                         /*
1176                         if (eval_non_null (area, reg)) {
1177                                 if (REPORT_ABC_REMOVAL)
1178                                         printf ("ARRAY-ACCESS: removed MONO_INST_FAULT flag.\n");
1179                                 ins->flags &= ~MONO_INST_FAULT;
1180                         } else {
1181                                 add_non_null (area, cfg, reg, &check_relations);
1182                         }
1183                         */
1184                 }
1185         }       
1186         
1187         if (TRACE_ABC_REMOVAL) {
1188                 printf ("Processing block %d [dfn %d] done.\n", bb->block_num, bb->dfn);
1189         }
1190         
1191         for (dominated_bb = bb->dominated; dominated_bb != NULL; dominated_bb = dominated_bb->next) {
1192                 process_block (cfg, (MonoBasicBlock*) (dominated_bb->data), area);
1193         }
1194
1195         for (l = check_relations; l; l = l->next)
1196                 remove_change_from_evaluation_area ((MonoAdditionalVariableRelation *)l->data);
1197         
1198         remove_change_from_evaluation_area (&(additional_relations.relation1));
1199         remove_change_from_evaluation_area (&(additional_relations.relation2));
1200 }
1201
1202 static MonoIntegerValueKind
1203 type_to_value_kind (MonoType *type)
1204 {
1205         if (type->byref)
1206                 return MONO_UNKNOWN_INTEGER_VALUE;
1207         switch (type->type) {
1208         case MONO_TYPE_I1:
1209                 return MONO_INTEGER_VALUE_SIZE_1;
1210                 break;
1211         case MONO_TYPE_U1:
1212                 return MONO_UNSIGNED_INTEGER_VALUE_SIZE_1;
1213                 break;
1214         case MONO_TYPE_I2:
1215                 return MONO_INTEGER_VALUE_SIZE_2;
1216                 break;
1217         case MONO_TYPE_U2:
1218                 return MONO_UNSIGNED_INTEGER_VALUE_SIZE_2;
1219                 break;
1220         case MONO_TYPE_I4:
1221                 return MONO_INTEGER_VALUE_SIZE_4;
1222                 break;
1223         case MONO_TYPE_U4:
1224                 return MONO_UNSIGNED_INTEGER_VALUE_SIZE_4;
1225                 break;
1226         case MONO_TYPE_I:
1227                 return (MonoIntegerValueKind)SIZEOF_VOID_P;
1228                 break;
1229         case MONO_TYPE_U:
1230                 return (MonoIntegerValueKind)(MONO_UNSIGNED_VALUE_FLAG | SIZEOF_VOID_P);
1231                 break;
1232         case MONO_TYPE_I8:
1233                 return MONO_INTEGER_VALUE_SIZE_8;
1234                 break;
1235         case MONO_TYPE_U8:
1236                 return MONO_UNSIGNED_INTEGER_VALUE_SIZE_8;
1237         default:
1238                 return MONO_UNKNOWN_INTEGER_VALUE;
1239         }
1240 }
1241
1242 /**
1243  * mono_perform_abc_removal:
1244  * @cfg: Control Flow Graph
1245  *
1246  * Performs the ABC removal from a cfg in SSA form.
1247  * It does the following:
1248  * - Prepare the evaluation area
1249  * - Allocate memory for the relation graph in the evaluation area
1250  *   (of course, only for variable definitions) and summarize there all
1251  *   variable definitions
1252  * - Allocate memory for the evaluation contexts in the evaluation area
1253  * - Recursively process all the BBs in the dominator tree (it is enough
1254  *   to invoke the processing on the entry BB)
1255  * 
1256  * cfg: the method code
1257  */
1258 void
1259 mono_perform_abc_removal (MonoCompile *cfg)
1260 {
1261         MonoVariableRelationsEvaluationArea area;
1262         MonoBasicBlock *bb;
1263         int i;
1264         
1265         verbose_level = cfg->verbose_level;
1266         
1267         if (TRACE_ABC_REMOVAL) {
1268                 printf ("\nRemoving array bound checks in %s\n", mono_method_full_name (cfg->method, TRUE));
1269         }
1270
1271         area.cfg = cfg;
1272         area.relations = (MonoSummarizedValueRelation *)
1273                 mono_mempool_alloc (cfg->mempool, sizeof (MonoSummarizedValueRelation) * (cfg->next_vreg) * 2);
1274
1275         area.contexts = (MonoRelationsEvaluationContext *)
1276                 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRelationsEvaluationContext) * (cfg->next_vreg));
1277
1278         area.statuses = (MonoRelationsEvaluationStatus *)
1279                 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRelationsEvaluationStatus) * (cfg->next_vreg));
1280
1281         area.variable_value_kind = (MonoIntegerValueKind *)
1282                 mono_mempool_alloc (cfg->mempool, sizeof (MonoIntegerValueKind) * (cfg->next_vreg));
1283         area.defs = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * cfg->next_vreg);
1284         for (i = 0; i < cfg->next_vreg; i++) {
1285                 area.variable_value_kind [i] = MONO_UNKNOWN_INTEGER_VALUE;
1286                 area.relations [i].relation = MONO_EQ_RELATION;
1287                 area.relations [i].relation_is_static_definition = TRUE;
1288                 MAKE_VALUE_ANY (area.relations [i].related_value);
1289                 area.relations [i].next = NULL;
1290                 area.defs [i] = NULL;
1291         }
1292
1293         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1294                 MonoInst *ins;
1295
1296                 if (TRACE_ABC_REMOVAL)
1297                         printf ("\nABCREM BLOCK %d:\n", bb->block_num);
1298
1299                 for (ins = bb->code; ins; ins = ins->next) {
1300                         const char *spec = INS_INFO (ins->opcode);
1301                         
1302                         if (spec [MONO_INST_DEST] == ' ' || MONO_IS_STORE_MEMBASE (ins))
1303                                 continue;
1304
1305                         if (spec [MONO_INST_DEST] == 'i') {
1306                                 MonoIntegerValueKind effective_value_kind;
1307                                 MonoRelationsEvaluationRange range;
1308                                 MonoSummarizedValueRelation *type_relation;
1309                                 MonoInst *var;
1310
1311                                 if (TRACE_ABC_REMOVAL)
1312                                         mono_print_ins (ins);
1313
1314                                 var = get_vreg_to_inst (cfg, ins->dreg);
1315                                 if (var)
1316                                         area.variable_value_kind [ins->dreg] = type_to_value_kind (var->inst_vtype);
1317
1318                                 effective_value_kind = get_relation_from_ins (&area, ins, &area.relations [ins->dreg], area.variable_value_kind [ins->dreg]);
1319
1320                                 MONO_MAKE_RELATIONS_EVALUATION_RANGE_WEAK (range);
1321                                 apply_value_kind_to_range (&range, area.variable_value_kind [ins->dreg]);
1322                                 apply_value_kind_to_range (&range, effective_value_kind);
1323                                         
1324                                 if (range.upper < INT_MAX) {
1325                                         type_relation = (MonoSummarizedValueRelation *) mono_mempool_alloc (cfg->mempool, sizeof (MonoSummarizedValueRelation));
1326                                         type_relation->relation = MONO_LE_RELATION;
1327                                         type_relation->related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
1328                                         type_relation->related_value.value.constant.value = range.upper;
1329                                         type_relation->relation_is_static_definition = TRUE;
1330                                         type_relation->next = area.relations [ins->dreg].next;
1331                                         area.relations [ins->dreg].next = type_relation;
1332                                         if (TRACE_ABC_REMOVAL) {
1333                                                 printf ("[var%d <= %d]", ins->dreg, range.upper);
1334                                         }
1335                                 }
1336                                 if (range.lower > INT_MIN) {
1337                                         type_relation = (MonoSummarizedValueRelation *) mono_mempool_alloc (cfg->mempool, sizeof (MonoSummarizedValueRelation));
1338                                         type_relation->relation = MONO_GE_RELATION;
1339                                         type_relation->related_value.type = MONO_CONSTANT_SUMMARIZED_VALUE;
1340                                         type_relation->related_value.value.constant.value = range.lower;
1341                                         type_relation->relation_is_static_definition = TRUE;
1342                                         type_relation->next = area.relations [ins->dreg].next;
1343                                         area.relations [ins->dreg].next = type_relation;
1344                                         if (TRACE_ABC_REMOVAL) {
1345                                                 printf ("[var%d >= %d]", ins->dreg, range.lower);
1346                                         }
1347                                 }
1348                                 if (TRACE_ABC_REMOVAL) {
1349                                         printf ("Summarized variable %d: ", ins->dreg);
1350                                         print_summarized_value (&(area.relations [ins->dreg].related_value));
1351                                         printf ("\n");
1352                                 }
1353                         }
1354                 }
1355         }
1356
1357         /* Add symmetric relations */
1358         for (i = 0; i < cfg->next_vreg; i++) {
1359                 if (area.relations [i].related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) {
1360                         int related_index = cfg->next_vreg + i;
1361                         int related_variable = area.relations [i].related_value.value.variable.variable;
1362                         
1363                         area.relations [related_index].relation = MONO_EQ_RELATION;
1364                         area.relations [related_index].relation_is_static_definition = TRUE;
1365                         area.relations [related_index].related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE;
1366                         area.relations [related_index].related_value.value.variable.variable = i;
1367                         area.relations [related_index].related_value.value.variable.delta = - area.relations [i].related_value.value.variable.delta;
1368                         
1369                         area.relations [related_index].next = area.relations [related_variable].next;
1370                         area.relations [related_variable].next = &(area.relations [related_index]);
1371                         
1372                         if (TRACE_ABC_REMOVAL) {
1373                                 printf ("Added symmetric summarized value for variable variable %d (to %d): ", i, related_variable);
1374                                 print_summarized_value (&(area.relations [related_index].related_value));
1375                                 printf ("\n");
1376                         }
1377                 }
1378         }
1379
1380         process_block (cfg, cfg->bblocks [0], &area);
1381 }
1382
1383 #endif /* DISABLE_JIT */