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