Changed header file usage (abcremoval.h).
[mono.git] / mono / mini / abcremoval.c
1
2 #include <string.h>
3 #include <stdio.h>
4
5 #include <mono/metadata/debug-helpers.h>
6 #include <mono/metadata/mempool.h>
7 #include <mono/metadata/opcodes.h>
8
9 #include "mini.h"
10 #include "inssel.h"
11
12 #include "abcremoval.h"
13
14 extern guint8 mono_burg_arity [];
15
16 #define TRACE_ABC_REMOVAL (verbose_level > 2)
17 #define REPORT_ABC_REMOVAL (verbose_level > 0)
18
19 #define CHEAT_AND_REMOVE_ALL_CHECKS 0
20
21 static int verbose_level;
22
23 #if (!CHEAT_AND_REMOVE_ALL_CHECKS)
24
25
26 #define IS_SUMMARIZED_VALUE_CONSTANT(value) ((value).value_type==MONO_CONSTANT_SUMMARIZED_VALUE)
27 #define IS_SUMMARIZED_VALUE_VARIABLE(value) ((value).value_type==MONO_VARIABLE_SUMMARIZED_VALUE)
28
29 #define RELATION_BETWEEN_VALUES(value,related_value) (\
30         ((value) > (related_value))? MONO_GT_RELATION :\
31         (((value) < (related_value))? MONO_LT_RELATION : MONO_EQ_RELATION))
32
33 #define MAKE_VALUE_ANY(v) do{\
34                 (v)->relation_with_zero = MONO_ANY_RELATION;\
35                 (v)->relation_with_one = MONO_ANY_RELATION;\
36                 (v)->relation_with_value = MONO_ANY_RELATION;\
37                 (v)->value_type = MONO_CONSTANT_SUMMARIZED_VALUE;\
38                 (v)->value.constant = 0;\
39         } while (0)
40
41 #define MONO_NEGATED_RELATION(r) ((~(r))&MONO_ANY_RELATION)
42 #define MONO_SYMMETRIC_RELATION(r) (((r)&MONO_EQ_RELATION)|(((r)&MONO_LT_RELATION)<<1)|((r&MONO_GT_RELATION)>>1))
43
44 #define RELATION_ADDS_INFORMATION(r,r_maybe_adds_information) ((r)&(~(r_maybe_adds_information)))
45
46 unsigned char propagated_relations_table [] = {
47         #include "propagated_relations_table.def"
48         MONO_ANY_RELATION
49 };
50 #define PROPAGATED_RELATION(r,r_to_propagate) (propagated_relations_table [((r)<<3)|(r_to_propagate)])
51
52
53 static void
54 print_relation (int relation) {
55         int print_or = 0;
56         printf ("(");
57         if (relation & MONO_LT_RELATION) {
58                 printf ("LT");
59                 print_or = 1;
60         }
61         if (relation & MONO_EQ_RELATION) {
62                 if (print_or) {
63                         printf ("|");
64                 }
65                 printf ("EQ");
66                 print_or = 1;
67         }
68         if (relation & MONO_GT_RELATION) {
69                 if (print_or) {
70                         printf ("|");
71                 }
72                 printf ("GT");
73                 print_or = 1;
74         }
75         printf (")");
76 }
77
78 static void
79 print_summarized_value (MonoSummarizedValue *value) {
80         printf ("relation_with_zero: ");
81         print_relation (value->relation_with_zero);
82         printf ("\n");
83         printf ("relation_with_one: ");
84         print_relation (value->relation_with_one);
85         printf ("\n");
86         printf ("relation_with_value: ");
87         print_relation (value->relation_with_value);
88         printf ("\n");
89         switch (value->value_type) {
90         case MONO_CONSTANT_SUMMARIZED_VALUE:
91                 printf ("Constant value: %d\n", value->value.constant);
92                 break;
93         case MONO_VARIABLE_SUMMARIZED_VALUE:
94                 printf ("Variable value: %d\n", value->value.variable);
95                 break;
96         case MONO_PHI_SUMMARIZED_VALUE: {
97                 int i;
98                 printf ("PHI value: (");
99                 for (i = 0; i < *(value->value.phi_variables); i++) {
100                         if (i) printf (",");
101                         printf ("%d", *(value->value.phi_variables + i + 1));
102                 }
103                 printf (")\n");
104                 break;
105         }
106         default:
107                 printf ("Unknown value type: %d\n", value->value_type);
108         }
109 }
110
111 static void
112 print_branch_condition (MonoBranchCondition *condition, int n) {
113         printf ("Branch condition %d, on variable %d\n", n, condition->variable);
114         print_summarized_value (&(condition->value));
115 }
116
117 static void
118 print_branch_data (MonoBranchData *branch, int n) {
119         int i;
120         printf ("Branch %d, destination BB %d [dfn %d], conditions %d\n",
121                 n, branch->destination_block->block_num, branch->destination_block->dfn, branch->number_of_conditions);
122         for (i = 0; i < branch->number_of_conditions; i++) {
123                 print_branch_condition (&(branch->conditions [i]), i);
124         }
125 }
126
127 static void
128 print_summarized_block (MonoSummarizedBasicBlock *block) {
129         int i;
130         printf ("Summarization of BB %d [dfn %d] (has array accesses: %d), branches: %d\n",
131                 block->block->block_num, block->block->dfn, block->has_array_access_instructions, block->number_of_branches);
132         for (i = 0; i < block->number_of_branches; i++) {
133                 print_branch_data (&(block->branches [i]), i);
134         }
135 }
136
137 static void
138 print_variable_relations (MonoVariableRelations *relations, gssize variable, int n) {
139         int i;
140         int significantRelations = 0;
141         for (i = 0; i < n; i++) {
142                 if (relations->relations_with_variables [i] != MONO_ANY_RELATION) {
143                         significantRelations++;
144                 }
145         }
146         if ((relations->relation_with_zero != MONO_ANY_RELATION) ||
147                         (relations->relation_with_one != MONO_ANY_RELATION) ||
148                         (significantRelations > 0)) {
149                 printf ("Relations for variable %d:\n", variable);
150                 if (relations->relation_with_zero != MONO_ANY_RELATION) {
151                         printf ("relation_with_zero: ");
152                         print_relation (relations->relation_with_zero);
153                         printf ("\n");
154                 }
155                 if (relations->relation_with_one != MONO_ANY_RELATION) {
156                         printf ("relation_with_one: ");
157                         print_relation (relations->relation_with_one);
158                         printf ("\n");
159                 }
160                 if (significantRelations > 0) {
161                         printf ("relations_with_variables (%d significant)\n", significantRelations);
162                         for (i = 0; i < n; i++) {
163                                 if (relations->relations_with_variables [i] != MONO_ANY_RELATION) {
164                                         printf ("relation with variable %d: ", i);
165                                         print_relation (relations->relations_with_variables [i]);
166                                         printf ("\n");
167                                 }
168                         }
169                 }
170         }
171 }
172
173 static void
174 print_all_variable_relations (MonoVariableRelationsEvaluationArea *evaluation_area) {
175         int i;
176         printf ("relations in evaluation area:\n");
177         for (i = 0; i < evaluation_area->cfg->num_varinfo; i++) {
178                 print_variable_relations (&(evaluation_area->variable_relations [i]), i, evaluation_area->cfg->num_varinfo);
179         }
180 }
181
182
183 static MonoValueRelation
184 relation_for_sum_of_variable_and_constant (
185                 MonoValueRelation variable_relation, MonoValueRelation constant_relation_with_zero) {
186         switch (variable_relation) {
187         case MONO_EQ_RELATION:
188                 return constant_relation_with_zero;
189         case MONO_GE_RELATION:
190                 if (constant_relation_with_zero & MONO_LT_RELATION) {
191                         return MONO_ANY_RELATION;
192                 } else {
193                         return constant_relation_with_zero;
194                 }
195         case MONO_LE_RELATION:
196                 if (constant_relation_with_zero & MONO_GT_RELATION) {
197                         return MONO_ANY_RELATION;
198                 } else {
199                         return constant_relation_with_zero;
200                 }
201         case MONO_GT_RELATION:
202                 if (constant_relation_with_zero & MONO_LT_RELATION) {
203                         return MONO_ANY_RELATION;
204                 } else {
205                         return MONO_GT_RELATION;
206                 }
207         case MONO_LT_RELATION:
208                 if (constant_relation_with_zero & MONO_GT_RELATION) {
209                         return MONO_ANY_RELATION;
210                 } else {
211                         return MONO_LE_RELATION;
212                 }
213         default:
214                 g_assert_not_reached ();
215                 return MONO_ANY_RELATION;
216         }
217 }
218
219 static MonoInst *
220 get_variable_value_from_ssa_store (MonoInst *store, int expected_variable_index) {
221         switch (store->opcode) {
222         case CEE_STIND_REF:
223         case CEE_STIND_I:
224         case CEE_STIND_I4:
225         case CEE_STIND_I1:
226         case CEE_STIND_I2:
227         case CEE_STIND_I8:
228         case CEE_STIND_R4:
229         case CEE_STIND_R8:
230                 if (TRACE_ABC_REMOVAL) {
231                         printf ("Store instruction found...\n");
232                 }
233                 if (store->inst_left->opcode == OP_LOCAL) {
234                         int variable_index = store->inst_left->inst_c0;
235                         if (TRACE_ABC_REMOVAL) {
236                                 printf ("Value put in local %d (expected %d)\n", variable_index, expected_variable_index);
237                         }
238                         if (variable_index == expected_variable_index) {
239                                 return store->inst_right;
240                         } else {
241                                 return NULL;
242                         }
243                 }
244                 else
245                 {
246                         return NULL;
247                 }
248                 break;
249         default:
250                 return NULL;
251         }
252 }
253
254 static void
255 summarize_value (MonoInst *value, MonoSummarizedValue *result) {
256         switch (value->opcode) {
257         case OP_ICONST:
258                 result->relation_with_zero = RELATION_BETWEEN_VALUES (value->inst_c0, 0);
259                 result->relation_with_one = RELATION_BETWEEN_VALUES (abs (value->inst_c0), 1);
260                 result->relation_with_value = MONO_EQ_RELATION;
261                 result->value_type = MONO_CONSTANT_SUMMARIZED_VALUE;
262                 result->value.constant = value->inst_c0;
263                 break;
264         case OP_LOCAL:
265         case OP_ARG:
266                 result->relation_with_zero = MONO_ANY_RELATION;
267                 result->relation_with_one = MONO_ANY_RELATION;
268                 result->relation_with_value = MONO_EQ_RELATION;
269                 result->value_type = MONO_VARIABLE_SUMMARIZED_VALUE;
270                 result->value.variable = value->inst_c0;
271                 break;
272         case CEE_LDIND_I4: {
273                 if ((value->inst_left->opcode == OP_LOCAL) || (value->inst_left->opcode == OP_ARG)) {
274                         summarize_value (value->inst_left, result);
275                 } else {
276                         MAKE_VALUE_ANY (result);
277                 }
278                 break;
279         }
280         case CEE_LDIND_REF:
281                 if ((value->inst_left->opcode == OP_LOCAL) || (value->inst_left->opcode == OP_ARG)) {
282                         summarize_value (value->inst_left, result);
283                 } else {
284                         MAKE_VALUE_ANY (result);
285                 }
286                 break;
287         case CEE_ADD:
288         case CEE_SUB: {
289                 MonoSummarizedValue left_value;
290                 MonoSummarizedValue right_value;
291                 summarize_value (value->inst_left, &left_value);
292                 summarize_value (value->inst_right, &right_value);
293
294                 if (IS_SUMMARIZED_VALUE_VARIABLE (left_value)) {
295                         if (IS_SUMMARIZED_VALUE_CONSTANT (right_value)&& (right_value.value.constant   = 1)) {
296                                 MonoValueRelation constant_relation_with_zero = right_value.relation_with_zero;
297                                 if (value->opcode == CEE_SUB) {
298                                         constant_relation_with_zero = MONO_SYMMETRIC_RELATION (constant_relation_with_zero);
299                                 }
300                                 result->relation_with_value = relation_for_sum_of_variable_and_constant (
301                                         left_value.relation_with_value, constant_relation_with_zero);
302                                 if (result->relation_with_value != MONO_ANY_RELATION) {
303                                         result->relation_with_zero = MONO_ANY_RELATION;
304                                         result->relation_with_one = MONO_ANY_RELATION;
305                                         result->value_type = MONO_VARIABLE_SUMMARIZED_VALUE;
306                                         result->value.variable = left_value.value.variable;
307                                 } else {
308                                         MAKE_VALUE_ANY (result);
309                                 }
310                         } else {
311                                 MAKE_VALUE_ANY (result);
312                         }
313                 } else if (IS_SUMMARIZED_VALUE_VARIABLE (right_value)) {
314                         if (IS_SUMMARIZED_VALUE_CONSTANT (left_value)&& (left_value.value.constant == 1)) {
315                                 MonoValueRelation constant_relation_with_zero = left_value.relation_with_zero;
316                                 if (value->opcode == CEE_SUB) {
317                                         constant_relation_with_zero = MONO_SYMMETRIC_RELATION (constant_relation_with_zero);
318                                 }
319                                 result->relation_with_value = relation_for_sum_of_variable_and_constant (
320                                         right_value.relation_with_value, constant_relation_with_zero);
321                                 if (result->relation_with_value != MONO_ANY_RELATION) {
322                                         result->relation_with_zero = MONO_ANY_RELATION;
323                                         result->relation_with_one = MONO_ANY_RELATION;
324                                         result->value_type = MONO_VARIABLE_SUMMARIZED_VALUE;
325                                         result->value.variable = right_value.value.variable;
326                                 } else {
327                                         MAKE_VALUE_ANY (result);
328                                 }
329                         } else {
330                                 MAKE_VALUE_ANY (result);
331                         }
332                 } else if (IS_SUMMARIZED_VALUE_CONSTANT (right_value)&& IS_SUMMARIZED_VALUE_CONSTANT (left_value)) {
333                         /* This should not happen if constant folding has been done */
334                         if (right_value.relation_with_value == MONO_EQ_RELATION && left_value.relation_with_value == MONO_EQ_RELATION) {
335                                 int constant;
336                                 if (value->opcode == CEE_ADD) {
337                                         constant = right_value.value.constant + left_value.value.constant;
338                                 }
339                                 else {
340                                         constant = right_value.value.constant - left_value.value.constant;
341                                 }
342                                 result->relation_with_zero = RELATION_BETWEEN_VALUES (constant, 0);
343                                 result->relation_with_one = RELATION_BETWEEN_VALUES (abs (constant), 1);
344                                 result->relation_with_value = MONO_EQ_RELATION;
345                                 result->value_type = MONO_CONSTANT_SUMMARIZED_VALUE;
346                                 result->value.constant = constant;
347                         } else {
348                                 MAKE_VALUE_ANY (result);
349                         }
350                 } else {
351                         MAKE_VALUE_ANY (result);
352                 }
353                 break;
354         }
355         case CEE_NEWARR:
356                 summarize_value (value->inst_newa_len, result);
357                 break;
358         case CEE_LDLEN:
359                 summarize_value (value->inst_left, result);
360                 break;
361         case OP_PHI:
362                 result->relation_with_zero = MONO_ANY_RELATION;
363                 result->relation_with_one = MONO_ANY_RELATION;
364                 result->relation_with_value = MONO_EQ_RELATION;
365                 result->value_type = MONO_PHI_SUMMARIZED_VALUE;
366                 result->value.phi_variables = value->inst_phi_args;
367                 break;
368         default:
369                 MAKE_VALUE_ANY (result);
370         }
371 }
372
373 static MonoValueRelation
374 get_relation_from_branch_instruction (int opcode) {
375         switch (opcode) {
376         case CEE_BEQ:
377                 return MONO_EQ_RELATION;
378         case CEE_BLT:
379         case CEE_BLT_UN:
380                 return MONO_LT_RELATION;
381         case CEE_BLE:
382         case CEE_BLE_UN:
383                 return MONO_LE_RELATION;
384         case CEE_BGT:
385         case CEE_BGT_UN:
386                 return MONO_GT_RELATION;
387         case CEE_BGE:
388         case CEE_BGE_UN:
389                 return MONO_GE_RELATION;
390         case CEE_BNE_UN:
391                 return MONO_NE_RELATION;
392         default:
393                 g_assert_not_reached ();
394                 return MONO_ANY_RELATION;
395         }
396 }
397
398 static int
399 contains_array_access (MonoInst *inst) {
400         if (inst->opcode == CEE_LDELEMA) { /* Handle OP_LDELEMA2D, too */
401                 return 1;
402         }
403
404         if (mono_burg_arity [inst->opcode]) {
405                 if (contains_array_access (inst->inst_left)) {
406                         return 1;
407                 }
408                 if (mono_burg_arity [inst->opcode] > 1) {
409                         return contains_array_access (inst->inst_right);
410                 }
411         }
412         return 0;
413 }
414
415 static void
416 analyze_block (MonoBasicBlock *bb, MonoVariableRelationsEvaluationArea *evaluation_area) {
417         MonoSummarizedBasicBlock *b = &(evaluation_area->blocks [bb->dfn]);
418         MonoInst *current_inst = bb->code;
419         MonoInst *last_inst = NULL;
420         int inst_index = 0;
421         
422         if (TRACE_ABC_REMOVAL) {
423                 printf ("Analyzing block %d [dfn %d]\n", bb->block_num, bb->dfn);
424         }
425         
426         g_assert (bb->dfn < evaluation_area->cfg->num_bblocks);
427         b->has_array_access_instructions = 0;
428         b->block = bb;
429         
430         while (current_inst != NULL) {
431                 if (TRACE_ABC_REMOVAL) {
432                         printf ("Analyzing instruction %d\n", inst_index);
433                         inst_index++;
434                 }
435                 
436                 if (contains_array_access (current_inst)) {
437                         b->has_array_access_instructions = 1;
438                 }
439                 
440                 if (current_inst->next == NULL) {
441                         last_inst = current_inst;
442                 }
443                 current_inst = current_inst->next;
444         }
445         
446         if (last_inst != NULL) {
447                 switch (last_inst->opcode) {
448                 case CEE_BEQ:
449                 case CEE_BLT:
450                 case CEE_BLE:
451                 case CEE_BGT:
452                 case CEE_BGE:
453                 case CEE_BNE_UN:
454                 case CEE_BLT_UN:
455                 case CEE_BLE_UN:
456                 case CEE_BGT_UN:
457                 case CEE_BGE_UN:
458                         if (last_inst->inst_left->opcode == OP_COMPARE) {
459                                 int number_of_variables = 0;
460                                 int current_variable = 0;
461                                 
462                                 MonoSummarizedValue left_value;
463                                 MonoSummarizedValue right_value;
464                                 MonoValueRelation relation = get_relation_from_branch_instruction (last_inst->opcode);
465                                 MonoValueRelation symmetric_relation = MONO_SYMMETRIC_RELATION (relation);
466                                 summarize_value (last_inst->inst_left->inst_left, &left_value);
467                                 summarize_value (last_inst->inst_left->inst_right, &right_value);
468                                 /* It is actually possible to handle some more case... */
469                                 if ((left_value.relation_with_value == MONO_EQ_RELATION) &&
470                                         (right_value.relation_with_value == MONO_EQ_RELATION)) {
471                                         if (left_value.value_type == MONO_VARIABLE_SUMMARIZED_VALUE)number_of_variables++;
472                                         if (right_value.value_type == MONO_VARIABLE_SUMMARIZED_VALUE)number_of_variables++;
473                                         if (number_of_variables > 0) {
474                                                 b->number_of_branches = 2;
475                                                 b->branches = (MonoBranchData*) mono_mempool_alloc (
476                                                         evaluation_area->pool, sizeof (MonoBranchData) * 2);
477                                                 MonoBranchData *branch_true = &(b->branches [0]);
478                                                 branch_true->destination_block = last_inst->inst_true_bb;
479                                                 branch_true->number_of_conditions = number_of_variables;
480                                                 branch_true->conditions = (MonoBranchCondition*)
481                                                         mono_mempool_alloc (evaluation_area->pool, sizeof (MonoBranchCondition) * number_of_variables);
482                                                 MonoBranchData *branch_false = &(b->branches [1]);
483                                                 branch_false->destination_block = last_inst->inst_false_bb;
484                                                 branch_false->number_of_conditions = number_of_variables;
485                                                 branch_false->conditions = (MonoBranchCondition*)
486                                                         mono_mempool_alloc (evaluation_area->pool, sizeof (MonoBranchCondition) * number_of_variables);
487                                                 if (left_value.value_type == MONO_VARIABLE_SUMMARIZED_VALUE) {
488                                                         MonoBranchCondition *condition_true = &(branch_true->conditions [current_variable]);
489                                                         condition_true->variable = left_value.value.variable;
490                                                         condition_true->value = right_value;
491                                                         condition_true->value.relation_with_zero = MONO_ANY_RELATION;
492                                                         condition_true->value.relation_with_one = MONO_ANY_RELATION;
493                                                         condition_true->value.relation_with_value = relation;
494                                                         MonoBranchCondition *condition_false = &(branch_false->conditions [current_variable]);
495                                                         condition_false->variable = left_value.value.variable;
496                                                         condition_false->value = right_value;
497                                                         condition_false->value.relation_with_zero = MONO_ANY_RELATION;
498                                                         condition_false->value.relation_with_one = MONO_ANY_RELATION;
499                                                         condition_false->value.relation_with_value = MONO_NEGATED_RELATION (relation);
500                                                         current_variable++;
501                                                 }
502                                                 if (right_value.value_type == MONO_VARIABLE_SUMMARIZED_VALUE) {
503                                                         MonoBranchCondition *condition_true = &(branch_true->conditions [current_variable]);
504                                                         condition_true->variable = right_value.value.variable;
505                                                         condition_true->value = left_value;
506                                                         condition_true->value.relation_with_zero = MONO_ANY_RELATION;
507                                                         condition_true->value.relation_with_one = MONO_ANY_RELATION;
508                                                         condition_true->value.relation_with_value = symmetric_relation;
509                                                         MonoBranchCondition *condition_false = &(branch_false->conditions [current_variable]);
510                                                         condition_false->variable = right_value.value.variable;
511                                                         condition_false->value = left_value;
512                                                         condition_false->value.relation_with_zero = MONO_ANY_RELATION;
513                                                         condition_false->value.relation_with_one = MONO_ANY_RELATION;
514                                                         condition_false->value.relation_with_value = MONO_NEGATED_RELATION (symmetric_relation);
515                                                 }
516                                         } else {
517                                                 b->number_of_branches = 0;
518                                                 b->branches = NULL;
519                                         }
520                                 } else {
521                                         b->number_of_branches = 0;
522                                         b->branches = NULL;
523                                 }
524                         } else {
525                                 b->number_of_branches = 0;
526                                 b->branches = NULL;
527                         }
528                         break;
529                 case CEE_SWITCH:
530                         /* Should handle switches... */
531                         /* switch_operand = last_inst->inst_right; */
532                         /* number_of_cases = GPOINTER_TO_INT (last_inst->klass); */
533                         /* cases = last_inst->inst_many_bb; */
534                         b->number_of_branches = 0;
535                         b->branches = NULL;
536                         break;
537                 default:
538                         b->number_of_branches = 0;
539                         b->branches = NULL;
540                 }
541         } else {
542                 b->number_of_branches = 0;
543                 b->branches = NULL;
544         }
545
546         if (TRACE_ABC_REMOVAL) {
547                 print_summarized_block (b);
548         }
549 }
550
551 #define SET_VARIABLE_RELATIONS(vr, relation, n)do {\
552         (vr)->relation_with_zero = (relation);\
553         (vr)->relation_with_one = (relation);\
554         memset ((vr)->relations_with_variables,(relation),(n));\
555 } while (0);
556
557 #define COMBINE_VARIABLE_RELATIONS(operator, vr, related_vr, n)do {\
558         int i;\
559         operator ((vr)->relation_with_zero, (related_vr)->relation_with_zero);\
560         operator ((vr)->relation_with_one, (related_vr)->relation_with_one);\
561         for (i = 0; i < (n); i++) {\
562                 operator ((vr)->relations_with_variables [i], (related_vr)->relations_with_variables [i]);\
563         }\
564 } while (0);
565
566 #define RELATION_ASSIGNMENT(destination,source) (destination)=(source)
567 #define RELATION_UNION(destination,source) (destination)|=(source)
568 #define RELATION_INTERSECTION(destination,source) (destination)&=(source)
569
570
571
572 static void
573 evaluate_variable_relations (gssize variable, MonoVariableRelationsEvaluationArea *evaluation_area, MonoRelationsEvaluationContext *father_context) {
574         MonoVariableRelations *relations = &(evaluation_area->variable_relations [variable]);
575         MonoRelationsEvaluationContext context;
576         if (TRACE_ABC_REMOVAL) {
577                 printf ("Applying definition of variable %d\n", variable);
578         }
579         context.father_context = father_context;
580         context.variable = variable;
581         switch (relations->evaluation_step) {
582         case MONO_RELATIONS_EVALUATION_NOT_STARTED: {
583                 MonoSummarizedValue *value = &(evaluation_area->variable_definitions [variable]);
584                 relations->evaluation_step = MONO_RELATIONS_EVALUATION_IN_PROGRESS;
585                 if (TRACE_ABC_REMOVAL) {
586                         printf ("Current step is MONO_RELATIONS_EVALUATION_NOT_STARTED, summarized value is:\n");
587                         print_summarized_value (value);
588                 }
589                 switch (value->value_type) {
590                 case MONO_CONSTANT_SUMMARIZED_VALUE:
591                         if (value->relation_with_value == MONO_EQ_RELATION) {
592                                 relations->relation_with_zero &= RELATION_BETWEEN_VALUES (value->value.constant, 0);
593                                 relations->relation_with_one &= RELATION_BETWEEN_VALUES (abs (value->value.constant), 1);
594                         }
595                         /* Other cases should not happen... */
596                         break;
597                 case MONO_VARIABLE_SUMMARIZED_VALUE: {
598                         gssize related_variable = value->value.variable;
599                         relations->relations_with_variables [related_variable] = value->relation_with_value;
600                         evaluate_variable_relations (related_variable, evaluation_area, &context);
601                         if (value->relation_with_value == MONO_EQ_RELATION) {
602                                 COMBINE_VARIABLE_RELATIONS (RELATION_INTERSECTION, relations,
603                                         &(evaluation_area->variable_relations [related_variable]), evaluation_area->cfg->num_varinfo);
604                         }
605                         /* Other cases should be handled... */
606                         break;
607                 }
608                 case MONO_PHI_SUMMARIZED_VALUE:
609                         if (value->relation_with_value == MONO_EQ_RELATION) {
610                                 int phi;
611                                 MonoVariableRelations *phi_union = (MonoVariableRelations*) alloca (sizeof (MonoVariableRelations));
612                                 phi_union->relations_with_variables = (unsigned char*) alloca (evaluation_area->cfg->num_varinfo);
613                                 SET_VARIABLE_RELATIONS (phi_union, MONO_NO_RELATION, evaluation_area->cfg->num_varinfo);
614                                 for (phi = 0; phi < *(value->value.phi_variables); phi++) {
615                                         gssize related_variable = value->value.phi_variables [phi+1];
616                                         evaluate_variable_relations (related_variable, evaluation_area, &context);
617                                         COMBINE_VARIABLE_RELATIONS (RELATION_UNION, phi_union,
618                                                 &(evaluation_area->variable_relations [related_variable]), evaluation_area->cfg->num_varinfo);
619                                 }
620                                 if (TRACE_ABC_REMOVAL) {
621                                         printf ("Resulting phi_union is:\n");
622                                         print_variable_relations (phi_union, variable, evaluation_area->cfg->num_varinfo);
623                                 }
624                                 COMBINE_VARIABLE_RELATIONS (RELATION_INTERSECTION, relations,
625                                         phi_union, evaluation_area->cfg->num_varinfo);
626                         }
627                         /* Other cases should not happen... */
628                         break;
629                 default:
630                         g_assert_not_reached ();
631                 }
632                 break;
633         }
634         case MONO_RELATIONS_EVALUATION_IN_PROGRESS: {
635                 MonoVariableRelations *recursive_value_relations = NULL;
636                 unsigned char recursive_relation = MONO_ANY_RELATION;
637                 MonoRelationsEvaluationContext *current_context = context.father_context;
638                 if (TRACE_ABC_REMOVAL) {
639                         printf ("Current step is MONO_RELATIONS_EVALUATION_IN_PROGRESS\n");
640                 }
641                 relations->definition_is_recursive = 1;
642                 while (current_context != NULL && current_context->variable != variable) {
643                         MonoVariableRelations *context_relations = &(evaluation_area->variable_relations [current_context->variable]);
644                         MonoSummarizedValue *context_value = &(evaluation_area->variable_definitions [current_context->variable]);
645                         if (TRACE_ABC_REMOVAL) {
646                                 printf ("Backtracing to context %d\n", current_context->variable);
647                         }
648                         if (recursive_value_relations == NULL) {
649                                 if (context_value->relation_with_value != MONO_EQ_RELATION) {
650                                         recursive_value_relations = context_relations;
651                                         recursive_relation = context_value->relation_with_value;
652                                         if (TRACE_ABC_REMOVAL) {
653                                                 printf ("Accepted recursive definition, relation is ");
654                                                 print_relation (recursive_relation);
655                                                 printf ("\n");
656                                         }
657                                 }
658                         } else {
659                                 if (context_value->relation_with_value != MONO_EQ_RELATION) {
660                                         recursive_relation = MONO_NO_RELATION;
661                                         if (TRACE_ABC_REMOVAL) {
662                                                 printf ("Rejected recursive definition, bad relation is ");
663                                                 print_relation (context_value->relation_with_value);
664                                                 printf ("\n");
665                                         }
666                                 }
667                         }
668                         current_context = current_context->father_context;
669                 }
670                 if (recursive_value_relations != NULL && recursive_relation != MONO_NO_RELATION) {
671                         int i;
672                         /* This should handle "grows" and "decreases" cases */
673                         recursive_value_relations->relation_with_zero &= recursive_relation;
674                         for (i = 0; i < evaluation_area->cfg->num_varinfo; i++) {
675                                 recursive_value_relations->relations_with_variables [i] &= recursive_relation;
676                         }
677                 }
678                 return;
679         }
680         case MONO_RELATIONS_EVALUATION_COMPLETED:
681                 if (TRACE_ABC_REMOVAL) {
682                         printf ("Current step is MONO_RELATIONS_EVALUATION_COMPLETED\n");
683                 }
684                 return;
685         default:
686                 g_assert_not_reached ();
687         }
688
689         relations->evaluation_step = MONO_RELATIONS_EVALUATION_COMPLETED;
690 }
691
692 static int
693 propagate_relations (MonoVariableRelationsEvaluationArea *evaluation_area) {
694         int changes = 0;
695         gssize variable;
696         for (variable = 0; variable < evaluation_area->cfg->num_varinfo; variable++) {
697                 MonoVariableRelations *relations = &(evaluation_area->variable_relations [variable]);
698                 gssize related_variable;
699                 for (related_variable = 0; related_variable < evaluation_area->cfg->num_varinfo; related_variable++) {
700                         unsigned char relation_with_variable = relations->relations_with_variables [related_variable];
701                         if (relation_with_variable != MONO_ANY_RELATION) {
702                                 MonoVariableRelations *related_relations = &(evaluation_area->variable_relations [related_variable]);
703                                 gssize variable_related_to_related_variable;
704                                 unsigned char new_relation_with_zero = PROPAGATED_RELATION (relation_with_variable, related_relations->relation_with_zero);
705                                 if (RELATION_ADDS_INFORMATION (relations->relation_with_zero, new_relation_with_zero)) {
706                                         if (TRACE_ABC_REMOVAL) {
707                                                 printf ("RELATION_ADDS_INFORMATION variable %d, related_variable %d, relation_with_zero ",
708                                                         variable, related_variable);
709                                                 print_relation (relations->relation_with_zero);
710                                                 printf (" - ");
711                                                 print_relation (new_relation_with_zero);
712                                                 printf (" => ");
713                                         }
714                                         relations->relation_with_zero &= new_relation_with_zero;
715                                         if (TRACE_ABC_REMOVAL) {
716                                                 print_relation (relations->relation_with_zero);
717                                                 printf ("\n");
718                                         }
719                                         changes++;
720                                 }
721                                 for (variable_related_to_related_variable = 0; variable_related_to_related_variable < evaluation_area->cfg->num_varinfo; variable_related_to_related_variable++) {
722                                         unsigned char relation_of_variable = related_relations->relations_with_variables [variable_related_to_related_variable];
723                                         unsigned char relation_with_other_variable = relations->relations_with_variables [variable_related_to_related_variable];
724                                         unsigned char new_relation_with_other_variable = PROPAGATED_RELATION (relation_with_variable, relation_of_variable);
725                                         if (RELATION_ADDS_INFORMATION (relation_with_other_variable, new_relation_with_other_variable)) {
726                                                 if (TRACE_ABC_REMOVAL) {
727                                                         printf ("RELATION_ADDS_INFORMATION variable %d, related_variable %d, variable_related_to_related_variable %d, ",
728                                                                 variable, related_variable, variable_related_to_related_variable);
729                                                         print_relation (relation_with_variable);
730                                                         printf (" - ");
731                                                         print_relation (new_relation_with_other_variable);
732                                                         printf (" => ");
733                                                 }
734                                                 relations->relations_with_variables [variable_related_to_related_variable] &= new_relation_with_other_variable;
735                                                 if (TRACE_ABC_REMOVAL) {
736                                                         print_relation (relations->relations_with_variables [variable_related_to_related_variable]);
737                                                         printf ("\n");
738                                                 }
739                                                 changes++;
740                                         }
741                                 }
742                         }
743                 }
744         }
745         return changes;
746 }
747
748 static void
749 remove_abc_from_inst (MonoInst *inst, MonoVariableRelationsEvaluationArea *evaluation_area) {
750         if (inst->opcode == CEE_LDELEMA) {
751                 MonoInst *array_inst = inst->inst_left;
752                 MonoInst *index_inst = inst->inst_right;
753                 /* Both the array and the index must be local variables */
754                 if ((array_inst->opcode == CEE_LDIND_REF) &&
755                                 ((array_inst->inst_left->opcode == OP_LOCAL)||(array_inst->inst_left->opcode == OP_ARG)) &&
756                                 ((index_inst->opcode == CEE_LDIND_I1) ||
757                                 (index_inst->opcode == CEE_LDIND_U1) ||
758                                 (index_inst->opcode == CEE_LDIND_I2) ||
759                                 (index_inst->opcode == CEE_LDIND_U2) ||
760                                 (index_inst->opcode == CEE_LDIND_I4) ||
761                                 (index_inst->opcode == CEE_LDIND_U4))&&
762                                 ((index_inst->inst_left->opcode == OP_LOCAL)||(index_inst->inst_left->opcode == OP_ARG))) {
763                         gssize array_variable = array_inst->inst_left->inst_c0;
764                         gssize index_variable = index_inst->inst_left->inst_c0;
765                         MonoVariableRelations *index_relations = &(evaluation_area->variable_relations [index_variable]);
766                         if ( (! (index_relations->relation_with_zero & ~MONO_GE_RELATION)) && 
767                                         (! (index_relations->relations_with_variables [array_variable] & ~MONO_LT_RELATION)) ) {
768                                 inst->flags |= (MONO_INST_NORANGECHECK);
769                         }
770                         if (TRACE_ABC_REMOVAL) {
771                                 if (! (index_relations->relation_with_zero & ~MONO_GE_RELATION)) {
772                                         printf ("ARRAY-ACCESS: Removed lower bound check on array %d with index %d\n", array_variable, index_variable);
773                                 } else {
774                                         printf ("ARRAY-ACCESS: Left lower bound check on array %d with index %d\n", array_variable, index_variable);
775                                 }
776                                 if (! (index_relations->relations_with_variables [array_variable] & ~MONO_LT_RELATION)) {
777                                         printf ("ARRAY-ACCESS: Removed upper bound check on array %d with index %d\n", array_variable, index_variable);
778                                 } else {
779                                         printf ("ARRAY-ACCESS: Left upper bound check on array %d with index %d\n", array_variable, index_variable);
780                                 }
781                         }
782                         if (REPORT_ABC_REMOVAL) {
783                                 if (inst->flags & (MONO_INST_NORANGECHECK)) {
784                                         printf ("ARRAY-ACCESS: removed bounds check on array %d with index %d in method %s\n",
785                                                 array_variable, index_variable, mono_method_full_name (evaluation_area->cfg->method, TRUE));
786                                 }
787                         }
788                 }
789         }
790         
791         if (mono_burg_arity [inst->opcode]) {
792                 remove_abc_from_inst (inst->inst_left, evaluation_area);
793                 if (mono_burg_arity [inst->opcode] > 1) {
794                         remove_abc_from_inst (inst->inst_right, evaluation_area);
795                 }
796         }
797 }
798
799 static void
800 remove_abc_from_block (MonoSummarizedBasicBlock *b, MonoVariableRelationsEvaluationArea *evaluation_area) {
801         int i;
802         int changes;
803         MonoBasicBlock *bb;
804         MonoInst *current_inst = b->block->code;
805         
806         if (TRACE_ABC_REMOVAL) {
807                 printf ("Working on block %d [dfn %d], has_array_access_instructions is %d\n",
808                         b->block->block_num, b->block->dfn, b->has_array_access_instructions);
809         }
810         
811         if (b->has_array_access_instructions) {
812                 for (i = 0; i < evaluation_area->cfg->num_varinfo; i++) {
813                         evaluation_area->variable_relations [i].evaluation_step = MONO_RELATIONS_EVALUATION_NOT_STARTED;
814                         evaluation_area->variable_relations [i].definition_is_recursive = 0;
815                         SET_VARIABLE_RELATIONS (&(evaluation_area->variable_relations [i]), MONO_ANY_RELATION, evaluation_area->cfg->num_varinfo);
816                 }
817                 
818                 bb = b->block;
819                 while (bb != NULL) {
820                         /* Walk up dominators tree to put conditions in area */
821                         int in_index = 0;
822                         /* for (in_index = 0; in_index < bb->in_count; in_index++) { */
823                         if (bb->in_count == 1) { /* Should write the code to "sum" conditions... */
824                                 int out_index;
825                                 MonoBasicBlock *in_bb = bb->in_bb [in_index];
826                                 MonoSummarizedBasicBlock *in_b = &(evaluation_area->blocks [in_bb->dfn]);
827                                 for (out_index = 0; out_index < in_b->number_of_branches; out_index++) {
828                                         if (in_b->branches [out_index].destination_block == bb) {
829                                                 MonoBranchData *branch;
830                                                 int condition_index;
831                                                 if (TRACE_ABC_REMOVAL) {
832                                                         printf ("Applying conditions of branch %d -> %d\n", in_b->block->block_num, bb->block_num);
833                                                 }
834                                                 branch = &(in_b->branches [out_index]);
835                                                 for (condition_index = 0; condition_index < branch->number_of_conditions; condition_index++) {
836                                                         MonoBranchCondition *condition = &(branch->conditions [condition_index]);
837                                                         MonoVariableRelations *relations = &(evaluation_area->variable_relations [condition->variable]);
838                                                         switch (condition->value.value_type) {
839                                                                 case MONO_CONSTANT_SUMMARIZED_VALUE: {
840                                                                         if (condition->value.relation_with_value == MONO_EQ_RELATION) {
841                                                                                 relations->relation_with_zero &= RELATION_BETWEEN_VALUES (condition->value.value.constant, 0);
842                                                                                 relations->relation_with_one &= RELATION_BETWEEN_VALUES (abs (condition->value.value.constant), 1);
843                                                                                 if (TRACE_ABC_REMOVAL) {
844                                                                                         printf ("Applied equality condition with constant to variable %d; relatrion with 0: ", condition->variable);
845                                                                                         print_relation (relations->relation_with_zero);
846                                                                                         printf ("\n");
847                                                                                 }
848                                                                         } else if (condition->value.value.constant == 0) {
849                                                                                 relations->relation_with_zero &= condition->value.relation_with_value;
850                                                                                 if (TRACE_ABC_REMOVAL) {
851                                                                                         printf ("Applied relation with 0 to variable %d: ", condition->variable);
852                                                                                         print_relation (relations->relation_with_zero);
853                                                                                         printf ("\n");
854                                                                                 }
855                                                                         }
856                                                                         /* Other cases should be handled */
857                                                                         break;
858                                                                 }
859                                                                 case MONO_VARIABLE_SUMMARIZED_VALUE: {
860                                                                         relations->relations_with_variables [condition->value.value.variable] &= condition->value.relation_with_value;
861                                                                         if (TRACE_ABC_REMOVAL) {
862                                                                                 printf ("Applied relation between variables %d and %d: ", condition->variable, condition->value.value.variable);
863                                                                                 print_relation (relations->relations_with_variables [condition->value.value.variable]);
864                                                                                 printf ("\n");
865                                                                         }
866                                                                         break;
867                                                                 }
868                                                                 default:
869                                                                         g_assert_not_reached (); /* PHIs are not OK here */
870                                                         }
871                                                 }
872                                         }
873                                 }
874                         }
875                         bb = bb->idom;
876                 }
877                 
878                 if (TRACE_ABC_REMOVAL) {
879                         printf ("Branch conditions applied... ");
880                         print_all_variable_relations (evaluation_area);
881                 }
882                 
883                 for (i = 0; i < evaluation_area->cfg->num_varinfo; i++) {
884                         evaluate_variable_relations (i, evaluation_area, NULL);
885                 }
886                 
887                 if (TRACE_ABC_REMOVAL) {
888                         printf ("Variable definitions applied... ");
889                         print_all_variable_relations (evaluation_area);
890                 }
891                 
892                 i = 0;
893                 do {
894                         changes = propagate_relations (evaluation_area);
895                         i++;
896                         if (TRACE_ABC_REMOVAL) {
897                                 printf ("Propagated %d changes\n", changes);
898                         }
899                 } while ((changes > 0) && (i < evaluation_area->cfg->num_varinfo));
900                 
901                 if (TRACE_ABC_REMOVAL) {
902                         printf ("Relations fully propagated... ");
903                         print_all_variable_relations (evaluation_area);
904                 }
905                 
906                 /* Area is ready, look for array access instructions */
907                 if (TRACE_ABC_REMOVAL) {
908                         printf ("Going after array accesses...\n");
909                 }
910                 while (current_inst != NULL) {
911                         remove_abc_from_inst (current_inst, evaluation_area);
912                         current_inst = current_inst->next;
913                 }
914         }
915 }
916
917 void
918 mono_perform_abc_removal (MonoCompile *cfg)
919 {
920         MonoVariableRelationsEvaluationArea evaluation_area;
921         int i;
922         verbose_level = cfg->verbose_level;
923         
924         
925         if (TRACE_ABC_REMOVAL) {
926                 printf ("Removing array bound checks in %s\n", mono_method_full_name (cfg->method, TRUE));
927         }
928         
929         if (cfg->num_varinfo > 250) {
930                 if (TRACE_ABC_REMOVAL) {
931                         printf ("Too many variables (%d), giving up...\n", cfg->num_varinfo);
932                 }
933                 return;
934         }
935         
936         evaluation_area.pool = mono_mempool_new ();
937         evaluation_area.cfg = cfg;
938         evaluation_area.variable_relations = (MonoVariableRelations *)
939                 mono_mempool_alloc (evaluation_area.pool, sizeof (MonoVariableRelations) * (cfg->num_varinfo));
940         //printf ("Allocated %d bytes for %d variable relations at pointer %p\n",
941         //      sizeof (MonoVariableRelations) * (cfg->num_varinfo), (cfg->num_varinfo), evaluation_area.variable_relations);
942         for (i = 0; i < cfg->num_varinfo; i++ ) {
943                 evaluation_area.variable_relations [i].relations_with_variables = (unsigned char *)
944                         mono_mempool_alloc (evaluation_area.pool, (cfg->num_varinfo));
945                 //printf ("Allocated %d bytes [%d] at pointer %p\n",
946                 //      cfg->num_varinfo, i, evaluation_area.variable_relations [i].relations_with_variables);
947         }
948         evaluation_area.variable_definitions = (MonoSummarizedValue *)
949                 mono_mempool_alloc (evaluation_area.pool, sizeof (MonoSummarizedValue) * (cfg->num_varinfo));
950         //printf ("Allocated %d bytes for %d variable definitions at pointer %p\n",
951         //      sizeof (MonoSummarizedValue) * (cfg->num_varinfo), (cfg->num_varinfo), evaluation_area.variable_definitions);
952         if (TRACE_ABC_REMOVAL) {
953                 printf ("Method contains %d variables\n", i);
954         }
955         for (i = 0; i < cfg->num_varinfo; i++) {
956                 if (cfg->vars [i]->def != NULL) {
957                         MonoInst *value = get_variable_value_from_ssa_store (cfg->vars [i]->def, i);
958                         if (value != NULL) {
959                                 summarize_value (value, evaluation_area.variable_definitions + i);
960                                 if (TRACE_ABC_REMOVAL) {
961                                         printf ("Summarized variable %d\n", i);
962                                         print_summarized_value (evaluation_area.variable_definitions + i);
963                                 }
964                         } else {
965                                 MAKE_VALUE_ANY (evaluation_area.variable_definitions + i);
966                                 if (TRACE_ABC_REMOVAL) {
967                                         printf ("Definition of variable %d is not a proper store\n", i);
968                                 }
969                         }
970                 } else {
971                         MAKE_VALUE_ANY (evaluation_area.variable_definitions + i);
972                         if (TRACE_ABC_REMOVAL) {
973                                 printf ("Variable %d has no definition, probably it is an argument\n", i);
974                                 print_summarized_value (evaluation_area.variable_definitions + i);
975                         }
976                 }
977         }
978         
979         evaluation_area.blocks = (MonoSummarizedBasicBlock *)
980                 mono_mempool_alloc (evaluation_area.pool, sizeof (MonoSummarizedBasicBlock) * (cfg->num_bblocks));
981         //printf ("Allocated %d bytes for %d blocks at pointer %p\n",
982         //      sizeof (MonoSummarizedBasicBlock) * (cfg->num_bblocks), (cfg->num_bblocks), evaluation_area.blocks);
983         
984         for (i = 0; i < cfg->num_bblocks; i++) {
985                 analyze_block (cfg->bblocks [i], &evaluation_area);
986         }
987         
988         for (i = 0; i < cfg->num_bblocks; i++) {
989                 remove_abc_from_block (&(evaluation_area.blocks [i]), &evaluation_area);
990         }
991         
992         mono_mempool_destroy (evaluation_area.pool);
993 }
994
995 #else
996 static void remove_abc (MonoInst *inst) {
997         if (inst->opcode == CEE_LDELEMA) {
998                 if (TRACE_ABC_REMOVAL||REPORT_ABC_REMOVAL) {
999                         printf ("Performing removal...\n");
1000                 }
1001                 inst->flags |= (MONO_INST_NORANGECHECK);
1002         }
1003         
1004         if (mono_burg_arity [inst->opcode]) {
1005                 remove_abc (inst->inst_left);
1006                 if (mono_burg_arity [inst->opcode] > 1) {
1007                         remove_abc (inst->inst_right);
1008                 }
1009         }
1010 }
1011
1012 void
1013 mono_perform_abc_removal (MonoCompile *cfg) {
1014         verbose_level = cfg->verbose_level;
1015         
1016         int i;
1017         #if (TRACE_ABC_REMOVAL)
1018         printf ("Removing array bound checks in %s\n", mono_method_full_name (cfg->method, TRUE));
1019         #endif
1020         
1021         for (i = 0; i < cfg->num_bblocks; i++) {
1022                 #if (TRACE_ABC_REMOVAL)
1023                 printf ("  Working on block %d [dfn %d]\n", cfg->bblocks [i]->block_num, i);
1024                 #endif
1025                 
1026                 MonoBasicBlock *bb = cfg->bblocks [i];
1027                 MonoInst *inst = bb->code;
1028                 while (inst != NULL) {
1029                         remove_abc (inst);
1030                         inst = inst->next;
1031                 }
1032         }
1033 }
1034 #endif