Mon Oct 15 10:37:15 CEST 2007 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / local-propagation.c
1 /*
2  * local-propagation.c: Local constant, copy and tree propagation.
3  *
4  * To make some sense of the tree mover, read mono/docs/tree-mover.txt
5  *
6  * Author:
7  *   Paolo Molaro (lupus@ximian.com)
8  *   Dietmar Maurer (dietmar@ximian.com)
9  *   Massimiliano Mantione (massi@ximian.com)
10  *
11  * (C) 2006 Novell, Inc.  http://www.novell.com
12  */
13
14
15 #include <string.h>
16 #include <stdio.h>
17
18 #include <mono/metadata/debug-helpers.h>
19 #include <mono/metadata/mempool.h>
20 #include <mono/metadata/opcodes.h>
21 #include "mini.h"
22
23
24 #define MONO_DEBUG_LOCAL_PROP 0
25 #define MONO_DEBUG_TREE_MOVER 0
26 #define MONO_DUMP_TREE_MOVER 0
27 #define MONO_APPLY_TREE_MOVER_TO_SINGLE_METHOD 0
28 #define MONO_APPLY_TREE_MOVER_TO_COUNTED_METHODS 0
29
30 struct TreeMoverActSlot;
31 /*
32  * A node describing one dependency between a tree and a local
33  */
34 typedef struct TreeMoverDependencyNode {
35         /* The local used in the tree */
36         struct TreeMoverActSlot *used_slot;
37         /* The local defined by the tree */
38         struct TreeMoverActSlot *affected_slot;
39         /* Next in the list of used locals */
40         struct TreeMoverDependencyNode *next_used_local;
41         /* Next in the list of affected locals */
42         struct TreeMoverDependencyNode *next_affected_local;
43         /* Previous in the list of affected locals */
44         struct TreeMoverDependencyNode *previous_affected_local;
45         /* False if the local is used in a tree that defines a used local */
46         guchar use_is_direct;
47 } TreeMoverDependencyNode;
48
49 struct TreeMoverTreeMove;
50 /*
51  * A node in a list of affected TreeMoverTreeMove
52  */
53 typedef struct TreeMoverAffectedMove {
54         struct TreeMoverTreeMove *affected_move;
55         struct TreeMoverAffectedMove *next_affected_move;
56 } TreeMoverAffectedMove;
57
58 /*
59  * A node in a list of TreeMoverDependencyFromDeadDefinition
60  */
61 typedef struct TreeMoverDependencyFromDeadDefinition {
62         /* The ACT slot of the defined local */
63         struct TreeMoverActSlot *defined_slot;
64         /* The definition that will hopefully be dead */
65         MonoInst *dead_definition;
66         /* Next in the list */
67         struct TreeMoverDependencyFromDeadDefinition *next;
68 } TreeMoverDependencyFromDeadDefinition;
69
70 /*
71  * A "tree move"
72  */
73 typedef struct TreeMoverTreeMove {
74         /* ACT slot of the defined local */
75         struct TreeMoverActSlot *defined_slot;
76         /* Code location of the definition */
77         MonoInst *definition;
78         /* Code location where the tree must be replaced with the local */
79         MonoInst **use;
80         /* Moves that must not be performed of we perform this one */
81         TreeMoverAffectedMove *affected_moves;
82         /* Definitions that must be dead to be allowed to perform this move */
83         struct TreeMoverDependencyFromDeadDefinition *slots_that_must_be_safe;
84         /* Next in the list of scheduled moves */
85         struct TreeMoverTreeMove *next;
86         /* The used tree accesses heap memory */
87         guchar tree_reads_memory;
88         /* A subsequent definitions makes this move globally safe */
89         guchar move_is_safe;
90         /* This move has been affected by something, ignore it */
91         guchar skip_this_move;
92         /* "tree forwarding" cannot continue for this definition */
93         guchar prevent_forwarding;
94 } TreeMoverTreeMove;
95
96 /*
97  * An ACT slot (there is one for each local in the ACT array)
98  */
99 typedef struct TreeMoverActSlot {
100         /* List of used locals (directly and indirectly) */
101         TreeMoverDependencyNode *used_locals;
102         /* Last element (so that we can move all the nodes quickly) */
103         TreeMoverDependencyNode *last_used_local;
104         /* List of affected locals (definitions that use this local) */
105         TreeMoverDependencyNode *affected_locals;
106         /* The current pending move */
107         TreeMoverTreeMove *pending_move;
108         /* True if the move has already met its use use */
109         guchar pending_move_is_ready;
110         /* See [W] flag */
111         guchar waiting_flag;
112         /* See [X] flag */
113         guchar unsafe_flag;
114         /* A "tree forwarding" is in progress */
115         guchar pending_move_is_forwarded;
116 } TreeMoverActSlot;
117
118 /*
119  * Main tree mover work area
120  */
121 typedef struct TreeMover {
122         /* Pool used for allocating everything */
123         MonoMemPool *pool;
124         /* Current method */
125         MonoCompile *cfg;
126         
127         /* Free (recycled) TreeMoverDependencyNode structs */
128         TreeMoverDependencyNode *free_nodes;
129         /* Free (recycled) TreeMoverTreeMove structs */
130         TreeMoverTreeMove *free_moves;
131
132         /* ACT array */
133         TreeMoverActSlot *ACT;
134         /* List of tree moves that could be performed */
135         TreeMoverTreeMove *scheduled_moves;
136
137         /* The following fields are reset at each tree traversal */
138         /* List of used locals */
139         TreeMoverDependencyNode *used_nodes;
140         /* Last node in the list (to free it in one block) */
141         TreeMoverDependencyNode *last_used_node;
142         /* The current tree cannot be moved (it can still receive moves!) */
143         guchar tree_has_side_effects;
144         /* The current tree reads heap locations */
145         guchar tree_reads_memory;
146 } TreeMover;
147
148 inline static TreeMoverDependencyNode*
149 tree_mover_new_node (TreeMover *tree_mover) {
150         TreeMoverDependencyNode *node;
151         
152         if (tree_mover->free_nodes != NULL) {
153                 node = tree_mover->free_nodes;
154                 tree_mover->free_nodes = tree_mover->free_nodes->next_used_local;
155                 node->next_used_local = NULL;
156                 node->next_affected_local = NULL;
157                 node->previous_affected_local = NULL;
158         } else {
159                 node = (TreeMoverDependencyNode*) mono_mempool_alloc0 (tree_mover->pool, sizeof (TreeMoverDependencyNode));
160         }
161         
162         return node;
163 }
164
165 inline static void
166 tree_mover_new_slot_move (TreeMover *tree_mover, TreeMoverActSlot *slot) {
167         TreeMoverTreeMove *move;
168         
169         if (tree_mover->free_moves != NULL) {
170                 move = tree_mover->free_moves;
171                 tree_mover->free_moves = tree_mover->free_moves->next;
172                 memset (move, 0, sizeof (TreeMoverTreeMove));
173         } else {
174                 move = (TreeMoverTreeMove*) mono_mempool_alloc0 (tree_mover->pool, sizeof (TreeMoverTreeMove));
175         }
176         
177         slot->pending_move = move;
178 }
179
180 inline static void
181 tree_mover_dispose_used_nodes (TreeMover *tree_mover) {
182         tree_mover->last_used_node->next_used_local = tree_mover->free_nodes;
183         tree_mover->free_nodes = tree_mover->used_nodes;
184         tree_mover->used_nodes = NULL;
185         tree_mover->last_used_node = NULL;
186 }
187
188 inline static void
189 tree_mover_dispose_slot_nodes (TreeMover *tree_mover, TreeMoverActSlot *slot) {
190         slot->last_used_local->next_used_local = tree_mover->free_nodes;
191         tree_mover->free_nodes = slot->used_locals;
192         slot->used_locals = NULL;
193         slot->last_used_local = NULL;
194 }
195
196 inline static void
197 tree_mover_dispose_slot_move (TreeMover *tree_mover, TreeMoverActSlot *slot) {
198         slot->pending_move->next = tree_mover->free_moves;
199         tree_mover->free_moves = slot->pending_move;
200         slot->pending_move = NULL;
201 }
202
203 inline static TreeMoverActSlot*
204 tree_mover_slot_from_index (TreeMover *tree_mover, int index) {
205         return & (tree_mover->ACT [index]);
206 }
207
208 inline static int
209 tree_mover_slot_to_index (TreeMover *tree_mover, TreeMoverActSlot *slot) {
210         return slot - tree_mover->ACT;
211 }
212
213 inline static void
214 tree_mover_add_used_node (TreeMover *tree_mover, TreeMoverActSlot *slot, gboolean use_is_direct) {
215         TreeMoverDependencyNode *node;
216         
217         node = tree_mover_new_node (tree_mover);
218         node->used_slot = slot;
219         node->affected_slot = NULL;
220         node->use_is_direct = use_is_direct;
221         if (tree_mover->last_used_node != NULL) {
222                 tree_mover->last_used_node->next_used_local = node;
223         } else {\
224                 tree_mover->used_nodes = node;
225         }\
226         tree_mover->last_used_node = node;
227 }
228
229 inline static void
230 tree_mover_link_affecting_node (TreeMoverDependencyNode *node, TreeMoverActSlot *affected_slot) {
231         TreeMoverActSlot *affecting_slot = node->used_slot;
232         node->affected_slot = affected_slot;
233         node->next_affected_local = affecting_slot->affected_locals;
234         affecting_slot->affected_locals = node;
235         if (node->next_affected_local != NULL) {
236                 node->next_affected_local->previous_affected_local = node;
237         }
238         node->previous_affected_local = NULL;
239 }
240
241 inline static void
242 tree_mover_unlink_affecting_node (TreeMoverDependencyNode *node) {
243         if (node->next_affected_local != NULL) {
244                 node->next_affected_local->previous_affected_local = node->previous_affected_local;
245         }
246         if (node->previous_affected_local != NULL) {
247                 node->previous_affected_local->next_affected_local = node->next_affected_local;
248         } else {
249                 TreeMoverActSlot *slot = node->used_slot;
250                 slot->affected_locals = node->next_affected_local;
251         }
252         node->next_affected_local = NULL;
253         node->previous_affected_local = NULL;
254         node->affected_slot = NULL;
255 }
256
257 inline static void
258 tree_mover_link_affected_moves (TreeMover *tree_mover, TreeMoverActSlot *source_slot, TreeMoverActSlot *destination_slot) {
259         TreeMoverAffectedMove *node = (TreeMoverAffectedMove*) mono_mempool_alloc0 (tree_mover->pool, sizeof (TreeMoverAffectedMove));
260         node->affected_move = destination_slot->pending_move; 
261         node->next_affected_move = source_slot->pending_move->affected_moves;
262         source_slot->pending_move->affected_moves = node;
263 }
264
265
266 inline static void
267 tree_mover_record_pending_move (TreeMover *tree_mover, TreeMoverActSlot *slot, gboolean move_is_safe) {
268         if (slot->pending_move_is_ready) {
269                 slot->pending_move->move_is_safe = move_is_safe;
270                 slot->pending_move->next = tree_mover->scheduled_moves;
271                 tree_mover->scheduled_moves = slot->pending_move;
272                 slot->pending_move = NULL;
273                 slot->pending_move_is_ready = FALSE;
274         }
275 }
276
277 inline static void
278 tree_mover_clear_forwarding_dependency (TreeMoverActSlot *slot) {
279         if (slot->pending_move_is_forwarded) {
280                 TreeMoverDependencyFromDeadDefinition *dependency = slot->pending_move->slots_that_must_be_safe;
281                 while (dependency != NULL) {
282                         if (dependency->defined_slot == slot) {
283                                 dependency->defined_slot = NULL;
284                         }
285                         dependency = dependency->next;
286                 }
287                 slot->pending_move = NULL;
288         }
289 }
290
291 inline static void
292 tree_mover_enforce_forwarding_dependency (TreeMoverActSlot *slot) {
293         if (slot->pending_move_is_forwarded) {
294                 slot->pending_move->skip_this_move = TRUE;
295                 slot->pending_move_is_forwarded = FALSE;
296                 slot->pending_move = NULL;
297         }
298 }
299
300 inline static void
301 tree_mover_clean_act_slot_dependency_nodes (TreeMover *tree_mover, TreeMoverActSlot *slot) {
302         TreeMoverDependencyNode *current_node = slot->used_locals;
303         while (current_node != NULL) {
304                 tree_mover_unlink_affecting_node (current_node);
305                 current_node = current_node->next_used_local;
306         }
307         if (slot->used_locals != NULL) {
308                 tree_mover_dispose_slot_nodes (tree_mover, slot);
309         }
310 }
311
312 inline static void
313 tree_mover_clean_act_slot_pending_move (TreeMover *tree_mover, TreeMoverActSlot *slot) {
314         if (slot->pending_move != NULL) {
315                 if (! slot->pending_move_is_forwarded) {
316                         tree_mover_dispose_slot_move (tree_mover, slot);
317                 } else {\
318                         slot->pending_move = NULL;
319                 }
320         }
321         slot->pending_move_is_ready = FALSE;
322         slot->pending_move_is_forwarded = FALSE;
323 }
324
325 inline static void
326 tree_mover_clean_act_slot (TreeMover *tree_mover, TreeMoverActSlot *slot) {
327         tree_mover_clean_act_slot_dependency_nodes (tree_mover, slot);
328         tree_mover_clean_act_slot_pending_move (tree_mover, slot);
329 }
330
331 inline static void
332 tree_mover_kill_act_slot_for_definition (TreeMover *tree_mover, TreeMoverActSlot *slot) {
333         tree_mover_record_pending_move (tree_mover, slot, TRUE);
334         tree_mover_clear_forwarding_dependency (slot);
335         tree_mover_clean_act_slot (tree_mover, slot);
336 }
337
338 inline static void
339 tree_mover_kill_act_slot_because_it_is_affected (TreeMover *tree_mover, TreeMoverActSlot *slot) {
340         if ((! slot->pending_move_is_ready) && (! slot->pending_move_is_forwarded)) {
341                 tree_mover_clean_act_slot (tree_mover, slot);
342         }
343 }
344
345 inline static void
346 tree_mover_kill_act_slot_for_use (TreeMover *tree_mover, TreeMoverActSlot *slot) {
347         tree_mover_enforce_forwarding_dependency (slot);
348         tree_mover_clean_act_slot (tree_mover, slot);
349 }
350
351 inline static void
352 tree_mover_kill_act_for_indirect_local_definition (TreeMover *tree_mover, int size) {
353         int i;
354         for (i = 0; i < size; i++) {
355                 TreeMoverActSlot *slot = &(tree_mover->ACT [i]);
356                 if (slot->pending_move != NULL) {
357                         slot->pending_move->prevent_forwarding = TRUE;
358                 }
359                 tree_mover_kill_act_slot_because_it_is_affected (tree_mover, slot);
360         }
361 }
362
363 inline static void
364 tree_mover_kill_act_for_indirect_global_definition (TreeMover *tree_mover, int size) {
365         int i;
366         for (i = 0; i < size; i++) {
367                 TreeMoverActSlot *slot = &(tree_mover->ACT [i]);
368                 if ((slot->pending_move != NULL) && slot->pending_move->tree_reads_memory) {
369                         tree_mover_kill_act_slot_because_it_is_affected (tree_mover, slot);
370                 }
371         }
372 }
373
374 inline static void
375 tree_mover_kill_act_for_indirect_use (TreeMover *tree_mover, int size) {
376         int i;
377         for (i = 0; i < size; i++) {
378                 TreeMoverActSlot *slot = &(tree_mover->ACT [i]);
379                 tree_mover_kill_act_slot_for_use (tree_mover, slot);
380         }
381 }
382
383 inline static void
384 tree_mover_clear_act_recording_moves (TreeMover *tree_mover, int size) {
385         int i;
386         for (i = 0; i < size; i++) {
387                 TreeMoverActSlot *slot = &(tree_mover->ACT [i]);
388                 tree_mover_record_pending_move (tree_mover, slot, FALSE);
389                 tree_mover_clean_act_slot (tree_mover, slot);
390         }
391 }
392
393 inline static void
394 tree_mover_set_waiting_flags (TreeMover *tree_mover, int size) {
395         int i;
396         for (i = 0; i < size; i++) {
397                 TreeMoverActSlot *slot = &(tree_mover->ACT [i]);
398                 slot->waiting_flag = TRUE;
399         }
400 }
401
402 inline static void
403 tree_mover_verify_dependency_nodes_are_clear (TreeMover *tree_mover, int size) {
404         int i;
405         for (i = 0; i < size; i++) {
406                 TreeMoverActSlot *slot = &(tree_mover->ACT [i]);
407                 if (slot->affected_locals != NULL) {
408                         printf ("Slot %d has still affected variables\n", i); 
409                         g_assert_not_reached ();
410                 }
411                 if (slot->used_locals != NULL) {
412                         printf ("Slot %d has still used variables\n", i); 
413                         g_assert_not_reached ();
414                 }
415                 if (slot->last_used_local != NULL) {
416                         printf ("Slot %d has still a last used variable\n", i); 
417                         g_assert_not_reached ();
418                 }
419         }
420 }
421
422
423 static const guchar stind_needs_conversion[(CEE_STIND_R8-CEE_STIND_REF)+1][STACK_MAX] = {
424         /* INV I4    I8    PTR   R8    MP    OBJ   VTYPE */
425         {TRUE ,TRUE, TRUE, FALSE,TRUE, FALSE,FALSE,TRUE}, /* CEE_STIND_REF */
426         {TRUE ,TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_STIND_I1  */
427         {TRUE ,TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_STIND_I2  */
428         {TRUE ,FALSE,TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_STIND_I4  */
429         {TRUE ,TRUE, FALSE,TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_STIND_I8  */
430         {TRUE ,TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_STIND_R4  */
431         {TRUE ,TRUE, TRUE, TRUE, FALSE,TRUE, TRUE, TRUE}  /* CEE_STIND_R8  */
432 };
433 static const guchar stind_i_needs_conversion[STACK_MAX] = {TRUE ,TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE};
434 static const guchar ldind_needs_conversion[(CEE_LDIND_REF-CEE_LDIND_I1)+1][STACK_MAX] = {
435         /* INV I4    I8    PTR   R8    MP    OBJ   VTYPE */
436         {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_LDIND_I1  */
437         {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_LDIND_U1  */
438         {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_LDIND_I2  */
439         {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_LDIND_U2  */
440         {TRUE, FALSE,TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_LDIND_I4  */
441         {TRUE, FALSE,TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_LDIND_U4  */
442         {TRUE, TRUE, FALSE,TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_LDIND_I8  */
443         {TRUE, TRUE, TRUE, FALSE,TRUE, FALSE,FALSE,TRUE}, /* CEE_LDIND_I   */
444         {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}, /* CEE_LDIND_R4  */
445         {TRUE, TRUE, TRUE, TRUE, FALSE,TRUE, TRUE, TRUE}, /* CEE_LDIND_R8  */
446         {TRUE, TRUE, TRUE, FALSE,TRUE, FALSE,FALSE,TRUE}  /* CEE_LDIND_REF */
447 };
448
449 #define TREE_MOVER_LDIND_TO_CONV(__opcode) (ldind_to_conv [(__opcode) - CEE_LDIND_I1])
450 #define TREE_MOVER_STIND_NEEDS_CONVERSION(__opcode,__type) (((__opcode) != CEE_STIND_I) ? (stind_needs_conversion [(__opcode) - CEE_STIND_REF][(__type)]) : (stind_i_needs_conversion [(__type)]))
451 #define TREE_MOVER_LDIND_NEEDS_CONVERSION(__opcode,__type) (ldind_needs_conversion [(__opcode) - CEE_LDIND_I1][(__type)])
452
453 static void
454 tree_mover_print_act_slot (const char* message, TreeMover *tree_mover, TreeMoverActSlot *slot) {
455         TreeMoverDependencyNode *node;
456         printf ("  [%s] Slot %d uses {", message, tree_mover_slot_to_index (tree_mover, slot));
457         for (node = slot->used_locals; node != NULL; node = node->next_used_local) {
458                 printf (" %d", tree_mover_slot_to_index (tree_mover, node->used_slot));
459         }
460         printf (" } affects {");
461         for (node = slot->affected_locals; node != NULL; node = node->next_affected_local) {
462                 printf (" %d", tree_mover_slot_to_index (tree_mover, node->affected_slot));
463         }
464         printf (" } R%d F%d W%d U%d", slot->pending_move_is_ready, slot->pending_move_is_forwarded, slot->waiting_flag, slot->unsafe_flag);
465         if (slot->pending_move != NULL) {
466                 printf (" DEFINITION:");
467                 //printf (" DEFINITION[%p]:", slot->pending_move->definition);
468                 mono_print_tree (slot->pending_move->definition);
469         }
470         printf ("\n");
471 }
472
473 static TreeMoverTreeMove*
474 mono_cprop_copy_values (MonoCompile *cfg, TreeMover *tree_mover, MonoInst *tree, MonoInst **acp)
475 {
476         MonoInst *cp;
477         int arity;
478         TreeMoverTreeMove *pending_move = NULL;
479
480         if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) &&
481             (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
482
483                 if (cp->opcode == OP_ICONST) {
484                         if (cfg->opt & MONO_OPT_CONSPROP) {
485                                 //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
486                                 if (MONO_DEBUG_LOCAL_PROP) {
487                                         printf ("Propagating constant, tree ");
488                                         mono_print_tree (tree);
489                                         printf (" becomes ");
490                                         mono_print_tree (cp);
491                                         printf ("\n");
492                                 }
493                                 *tree = *cp;
494                         }
495                 } else {
496                         MonoType *inst_i0_underlying_type = mono_type_get_underlying_type (tree->inst_i0->inst_vtype);
497                         MonoType *cp_underlying_type = mono_type_get_underlying_type (cp->inst_vtype);
498                         if ((inst_i0_underlying_type->type == cp_underlying_type->type) ||
499                             (tree->type == STACK_OBJ) || (tree->type == STACK_MP)) {
500                                 if (cfg->opt & MONO_OPT_COPYPROP) {
501                                         //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
502                                         if (MONO_DEBUG_LOCAL_PROP) {
503                                                 printf ("Propagating value, tree->inst_i0 ");
504                                                 mono_print_tree (tree->inst_i0);
505                                                 printf (" becomes ");
506                                                 mono_print_tree (cp);
507                                                 printf ("\n");
508                                         }
509                                         tree->inst_i0 = cp;
510                                 }
511                         } else if (MONO_DEBUG_LOCAL_PROP) {
512                                 char* tree_type_name = mono_type_full_name (tree->inst_i0->inst_vtype);
513                                 char* cp_type_name = mono_type_full_name (cp->inst_vtype);
514                                 printf ("Values of tree->inst_i0 ");
515                                 mono_print_tree (tree->inst_i0);
516                                 printf (" and cp ");
517                                 mono_print_tree (cp);
518                                 printf (" have incompatible types in tree ");
519                                 mono_print_tree (tree);
520                                 printf ("\n");
521                                 printf (" MonoType of tree->inst_i0 is: %s\n", tree_type_name);
522                                 printf (" MonoType of cp is: %s\n", cp_type_name);
523                                 g_free (tree_type_name);
524                                 g_free (cp_type_name);
525                         }
526                 }
527         } else {
528                 if (MONO_DEBUG_LOCAL_PROP) {
529                         printf ("Propagation SKIPPED for inst ");
530                         mono_print_tree (tree);
531                         printf ("\n");
532                 }
533                 if ((tree_mover != NULL) && (cfg->opt & MONO_OPT_CFOLD))
534                         mono_constant_fold_inst (tree, NULL);
535
536                 arity = mono_burg_arity [tree->opcode];
537
538                 if (arity) {
539                         TreeMoverTreeMove *result = mono_cprop_copy_values (cfg, tree_mover, tree->inst_i0, acp);
540                         if (cfg->opt & MONO_OPT_CFOLD)
541                                 mono_constant_fold_inst (tree, NULL);
542                         if (result != NULL) {
543                                 result->use = &(tree->inst_i0);
544                                 //printf (" SETTING inst_i0[%p] USE to %p (definition is %p)\n", tree, result->use, result->definition);
545
546                         }
547                         /* The opcode may have changed */
548                         if (mono_burg_arity [tree->opcode] > 1) {
549                                 if (cfg->opt & MONO_OPT_CFOLD)
550                                         mono_constant_fold_inst (tree, NULL);
551                                 result = mono_cprop_copy_values (cfg, tree_mover, tree->inst_i1, acp);
552                                 if (result != NULL) {
553                                         result->use = &(tree->inst_i1);
554                                         //printf (" SETTING inst_i1[%p] USE to %p (definition is %p)\n", tree, result->use, result->definition);
555                                 }
556                         }
557                         mono_constant_fold_inst (tree, NULL);
558                 }
559         }
560         
561         /* Apply the tree mover after after propagation has been done */
562         if ((tree_mover != NULL) && (tree->ssa_op == MONO_SSA_LOAD) &&
563                         (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
564                 guint used_index = tree->inst_i0->inst_c0;
565                 TreeMoverActSlot *used_slot = &(tree_mover->ACT [used_index]);
566                 
567                 /* First, handle waiting flag */
568                 if (used_slot->waiting_flag) {
569                         used_slot->unsafe_flag = TRUE;
570                         used_slot->waiting_flag = FALSE;
571                 }
572
573                 if (!tree->inst_i0->flags) {
574                         /* Record local use (the tree that contains this use might be movable) */
575                         tree_mover_add_used_node (tree_mover, used_slot, TRUE);
576
577                         /* Start working on the pending move... */
578                         pending_move = used_slot->pending_move;
579
580                         /* If there *is* a pending move... (otherwise, do nothing) */
581                         if (pending_move != NULL) {
582                                 /* Check slot state */
583                                 if (used_slot->pending_move_is_forwarded) {
584                                         /* If the slot was a "hopefully dead" definition because of a forwarding... */
585                                         if (MONO_DEBUG_TREE_MOVER) {
586                                                 printf ("Use should have been dead, killing slot %d: ", used_index);
587                                                 mono_print_tree_nl (tree);
588                                                 printf ("Also disabling forwarded definition at slot %d: ", tree_mover_slot_to_index (tree_mover, pending_move->defined_slot));
589                                                 mono_print_tree_nl (pending_move->definition);
590                                         }
591                                         /* ...clear the slot (which also disables the forwarded definition), and... */
592                                         tree_mover_kill_act_slot_for_use (tree_mover, used_slot);
593                                         /* ...clear the pending_move */
594                                         pending_move = NULL;
595                                 } else if (used_slot->pending_move_is_ready ||
596                                                 TREE_MOVER_STIND_NEEDS_CONVERSION (pending_move->definition->opcode, pending_move->definition->inst_i1->type) ||
597                                                 TREE_MOVER_LDIND_NEEDS_CONVERSION (tree->opcode, pending_move->definition->inst_i1->type)) {
598                                         /* If the move was already in state [U], or if there are type problems... */
599                                         if (MONO_DEBUG_TREE_MOVER) {
600                                                 printf ("Definition has too many, wrong or misplaced uses, killing slot %d: ", used_index);
601                                                 mono_print_tree_nl (tree);
602                                         }
603                                         /* ...kill it, and clear the pending_move */
604                                         tree_mover_kill_act_slot_for_use (tree_mover, used_slot);
605                                         pending_move = NULL;
606                                 } else {
607                                         /* All goes well: set slot state to [U] */
608                                         TreeMoverDependencyNode *node = used_slot->used_locals;
609                                         if (MONO_DEBUG_TREE_MOVER) {
610                                                 printf ("Setting tree move for slot %d as ready: ", used_index);
611                                                 mono_print_tree_nl (tree);
612                                         }
613                                         /* Record indirect uses generated by this move */
614                                         while (node != NULL) {
615                                                 tree_mover_add_used_node (tree_mover, node->used_slot, FALSE);
616                                                 node = node->next_used_local;
617                                         }
618
619                                         /* Setup tree as movable */
620                                         used_slot->pending_move_is_ready = TRUE;
621                                 }
622                         }
623                 } else {
624                         if (MONO_DEBUG_TREE_MOVER) {
625                                 printf ("Tree has side effects, killing slot %d: ", used_index);
626                                 mono_print_tree_nl (tree);
627                         }
628                         /* The whole tree is unmovable (it uses a flagged local) */
629                         tree_mover->tree_has_side_effects = TRUE;
630                         /* Moreover, the use of a flagged local kills the definition */
631                         tree_mover_kill_act_slot_for_use (tree_mover, used_slot);
632                 }
633 #if MONO_DUMP_TREE_MOVER
634                 tree_mover_print_act_slot ("USE", tree_mover, used_slot);
635 #endif
636         }       
637         return pending_move;
638 }
639
640 static void
641 mono_cprop_invalidate_values (MonoInst *tree, TreeMover *tree_mover, MonoInst **acp, int acp_size)
642 {
643         int arity;
644
645         if (tree_mover != NULL) {
646                 if ((tree->opcode == CEE_NEWARR) || (mono_find_jit_opcode_emulation (tree->opcode) != NULL)) {
647                         if (MONO_DEBUG_TREE_MOVER) {
648                                 printf ("Recording side effect because emulated opcode cannot be moved: ");
649                                 mono_print_tree_nl (tree);
650                         }
651                         tree_mover->tree_has_side_effects = TRUE;
652                 }
653         }
654
655         switch (tree->opcode) {
656         case CEE_LDIND_REF:
657         case CEE_LDIND_I1:
658         case CEE_LDIND_I2:
659         case CEE_LDIND_I4:
660         case CEE_LDIND_U1:
661         case CEE_LDIND_U2:
662         case CEE_LDIND_U4:
663         case CEE_LDIND_I8:
664         case CEE_LDIND_R4:
665         case CEE_LDIND_R8:
666         case CEE_LDIND_I:
667         case CEE_LDOBJ:
668                 if ((tree_mover != NULL) && ((tree->ssa_op == MONO_SSA_NOP) || (tree->ssa_op & MONO_SSA_ADDRESS_TAKEN))) {
669                         if (MONO_DEBUG_TREE_MOVER) {
670                                 printf ("Recording memory read at inst: ");
671                                 mono_print_tree_nl (tree);
672                         }
673                         tree_mover->tree_reads_memory = TRUE;
674                 }
675                 break;
676         case CEE_STIND_I:
677         case CEE_STIND_I1:
678         case CEE_STIND_I2:
679         case CEE_STIND_I4:
680         case CEE_STIND_REF:
681         case CEE_STIND_I8:
682         case CEE_STIND_R4:
683         case CEE_STIND_R8:
684         case CEE_STOBJ:
685                 if ((tree->ssa_op == MONO_SSA_NOP) || (tree->ssa_op & MONO_SSA_ADDRESS_TAKEN)) {
686                         if (MONO_DEBUG_LOCAL_PROP) {
687                                 printf ("Indirect store clears ACP at tree ");
688                                 mono_print_tree (tree);
689                                 printf ("\n");
690                         }
691                         memset (acp, 0, sizeof (MonoInst *) * acp_size);
692                         if (tree_mover != NULL) {
693                                 if (MONO_DEBUG_TREE_MOVER) {
694                                         printf ("Killing all active slots (and recording side effect) because of inst ");
695                                         mono_print_tree_nl (tree);
696                                 }
697                                 /* Note that this does *not* dispose ready moves (state [U]) */
698                                 tree_mover_kill_act_for_indirect_local_definition (tree_mover, acp_size);
699                                 tree_mover->tree_has_side_effects = TRUE;
700                         }
701                         return;
702                 }
703
704                 break;
705         case CEE_CALL:
706         case OP_CALL_REG:
707         case CEE_CALLVIRT:
708         case OP_LCALL_REG:
709         case OP_LCALLVIRT:
710         case OP_LCALL:
711         case OP_FCALL_REG:
712         case OP_FCALLVIRT:
713         case OP_FCALL:
714         case OP_VCALL_REG:
715         case OP_VCALLVIRT:
716         case OP_VCALL:
717         case OP_VOIDCALL_REG:
718         case OP_VOIDCALLVIRT:
719         case OP_VOIDCALL: {
720                 MonoCallInst *call = (MonoCallInst *)tree;
721                 MonoMethodSignature *sig = call->signature;
722                 int i, byref = FALSE;
723
724                 if (tree_mover != NULL) {
725                         if (MONO_DEBUG_TREE_MOVER) {
726                                 printf ("Recording side effect because of inst ");
727                                 mono_print_tree_nl (tree);
728                         }
729                         tree_mover->tree_has_side_effects = TRUE;
730                 }
731
732                 for (i = 0; i < sig->param_count; i++) {
733                         if (sig->params [i]->byref) {
734                                 byref = TRUE;
735                                 break;
736                         }
737                 }
738
739                 if (byref) {
740                         if (MONO_DEBUG_LOCAL_PROP) {
741                                 printf ("Call with byref parameter clears ACP at tree ");
742                                 mono_print_tree (tree);
743                                 printf ("\n");
744                         }
745                         memset (acp, 0, sizeof (MonoInst *) * acp_size);
746                         if (tree_mover != NULL) {
747                                 if (MONO_DEBUG_TREE_MOVER) {
748                                         printf ("Killing all active slots because of inst ");
749                                         mono_print_tree_nl (tree);
750                                 }
751                                 tree_mover_kill_act_for_indirect_use (tree_mover, acp_size);
752                         }
753                 } else {
754                         if (tree_mover != NULL) {
755                                 if (MONO_DEBUG_TREE_MOVER) {
756                                         printf ("Killing all active slots reading memory because of inst ");
757                                         mono_print_tree_nl (tree);
758                                 }
759                                 tree_mover_kill_act_for_indirect_global_definition (tree_mover, acp_size);
760                         }
761                 }
762                 return;
763         }
764 #define TREEMOVE_SPECIFIC_OPS 1
765 #define OPDEF(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) case a1:
766 #include "simple-cee-ops.h"
767 #undef OPDEF
768 #define MINI_OP(a1,a2) case a1:
769 #include "simple-mini-ops.h"
770 #undef MINI_OP
771 #undef TREEMOVE_SPECIFIC_OPS
772                 break;
773         default:
774                 if (tree_mover != NULL) {
775                         if (MONO_DEBUG_TREE_MOVER) {
776                                 printf ("Recording side effect because of inst ");
777                                 mono_print_tree_nl (tree);
778                         }
779                         tree_mover->tree_has_side_effects = TRUE;
780                 }
781                 break;
782         }
783
784         arity = mono_burg_arity [tree->opcode];
785
786         switch (arity) {
787         case 0:
788                 break;
789         case 1:
790                 mono_cprop_invalidate_values (tree->inst_i0, tree_mover, acp, acp_size);
791                 break;
792         case 2:
793                 mono_cprop_invalidate_values (tree->inst_i0, tree_mover, acp, acp_size);
794                 mono_cprop_invalidate_values (tree->inst_i1, tree_mover, acp, acp_size);
795                 break;
796         default:
797                 g_assert_not_reached ();
798         }
799 }
800
801 static void
802 mono_local_cprop_bb (MonoCompile *cfg, TreeMover *tree_mover, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
803 {
804         MonoInst *tree = bb->code;
805         int i;
806
807         if (!tree)
808                 return;
809
810         if (tree_mover != NULL) {
811                 tree_mover_set_waiting_flags (tree_mover, acp_size);
812                 if (MONO_DEBUG_TREE_MOVER) {
813                         printf ("Running tree mover on BB%d\n", bb->block_num);
814                 }
815         }
816         for (; tree; tree = tree->next) {
817                 if (tree_mover != NULL) {
818                         if (MONO_DEBUG_TREE_MOVER) {
819                                 printf ("Running tree mover on tree ");
820                                 mono_print_tree_nl (tree);
821                         }
822                         tree_mover->tree_has_side_effects = FALSE;
823                         tree_mover->tree_reads_memory = FALSE;
824                 }
825
826                 mono_cprop_copy_values (cfg, tree_mover, tree, acp);
827                 mono_cprop_invalidate_values (tree, tree_mover, acp, acp_size);
828                 if (MONO_DEBUG_TREE_MOVER) {
829                         if (tree_mover != NULL) {
830                                 printf ("After the tree walk, tree_mover->tree_has_side_effects is %d\n", tree_mover->tree_has_side_effects);
831                         }
832                 }
833
834                 if (tree->ssa_op == MONO_SSA_STORE  &&
835                     (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
836                         MonoInst *i1 = tree->inst_i1;
837                         TreeMoverActSlot *forwarding_source = NULL;
838                         gboolean tree_can_be_moved = TRUE;
839
840                         acp [tree->inst_i0->inst_c0] = NULL;
841                         if (MONO_DEBUG_TREE_MOVER) {
842                                 printf ("Assignment clears ACP[%d] at tree ", tree->inst_i0->inst_c0);
843                                 mono_print_tree (tree);
844                                 printf ("\n");
845                         }
846
847                         for (i = 0; i < acp_size; i++) {
848                                 if (acp [i] && acp [i]->opcode != OP_ICONST &&
849                                     acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
850                                         acp [i] = NULL;
851                                         if (MONO_DEBUG_LOCAL_PROP) {
852                                                 printf ("  Consequently, ACP[%d] is cleared\n", i);
853                                         }
854                                 }
855                         }
856                         
857                         if (i1->opcode == OP_ICONST) {
858                                 acp [tree->inst_i0->inst_c0] = i1;
859                                 tree_can_be_moved = FALSE;
860                                 if (MONO_DEBUG_LOCAL_PROP) {
861                                         printf ("  Consequently, ACP[%ld] becomes constant ", (long)tree->inst_i0->inst_c0);
862                                         mono_print_tree (i1);
863                                         printf ("\n");
864                                 }
865                                 //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
866                         } else if ((i1->type==STACK_I8) || (i1->opcode==OP_I8CONST) || (i1->opcode==OP_R4CONST) || (i1->opcode==OP_R8CONST) || (i1->opcode==OP_AOTCONST)) {
867                                 tree_can_be_moved = FALSE;
868                                 if (MONO_DEBUG_TREE_MOVER) {
869                                         printf ("Preventing move of constant or long value ");
870                                         mono_print_tree (i1);
871                                         printf ("\n");
872                                 }
873                         }
874                         if (i1->ssa_op == MONO_SSA_LOAD &&
875                             (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
876                             (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
877                                 acp [tree->inst_i0->inst_c0] = i1->inst_i0;
878                                 tree_can_be_moved = FALSE;
879                                 if (MONO_DEBUG_LOCAL_PROP) {
880                                         printf ("  Consequently, ACP[%d] becomes local ", tree->inst_i0->inst_c0);
881                                         mono_print_tree (i1->inst_i0);
882                                         printf ("\n");
883                                 }
884                                 if (tree_mover != NULL) {
885                                         /* Examine the variable *used* in this definition (the "source") */
886                                         forwarding_source = tree_mover_slot_from_index (tree_mover, i1->inst_i0->inst_c0);
887                                         /* Check if source slot is ready to be forwarded */
888                                         if ((! forwarding_source->pending_move_is_ready) || (forwarding_source->pending_move->prevent_forwarding)) {
889                                                 /* no forwarding is possible, do nothing */
890                                                 forwarding_source = NULL;
891                                         }
892                                 }
893                                 //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
894                         }
895                         
896                         /* Apply tree mover */
897                         if (tree_mover != NULL) {
898                                 guint defined_index = tree->inst_i0->inst_c0;
899                                 TreeMoverActSlot *defined_slot = tree_mover_slot_from_index (tree_mover, defined_index);
900                                 TreeMoverDependencyNode *affected_node;
901                                 
902                                 /* First clear the waiting flag... */
903                                 defined_slot->waiting_flag = FALSE;
904                                 /* ...and kill this slot (but recording any pending move)*/
905                                 tree_mover_kill_act_slot_for_definition (tree_mover, defined_slot);
906                                 if (MONO_DEBUG_TREE_MOVER) {
907                                         printf ("Definition is clearing slot %d\n", defined_index);
908                                 }
909
910                                 /* Handle "used" nodes... */
911                                 /* Check if this is a forwarding */
912                                 if (forwarding_source == NULL) {
913                                         /* Normal case, no forwarding: */
914                                         /* Check that consprop or copyprop did not already do the job, */
915                                         /* and that the tree has no side effects */
916                                         if (tree_can_be_moved && ! tree_mover->tree_has_side_effects) {
917                                                 TreeMoverDependencyNode *affecting_node;
918                                                 if (MONO_DEBUG_TREE_MOVER) {
919                                                         printf ("Recording definition of slot %d by tree: ", defined_index);
920                                                         mono_print_tree_nl (tree);
921                                                 }
922
923                                                 /* Then apply the definition */
924                                                 tree_mover_new_slot_move (tree_mover, defined_slot);
925                                                 defined_slot->pending_move->definition = tree;
926                                                 defined_slot->pending_move->defined_slot = defined_slot;
927                                                 defined_slot->pending_move->tree_reads_memory = tree_mover->tree_reads_memory;
928
929                                                 /* Setup "used nodes" list */
930                                                 defined_slot->used_locals = tree_mover->used_nodes;
931                                                 defined_slot->last_used_local = tree_mover->last_used_node;
932                                                 tree_mover->used_nodes = NULL;
933                                                 tree_mover->last_used_node = NULL;
934                                                 /* Link used nodes to "affecting" slots (so affected variables are linked) */
935                                                 /* This is needed *now* so that circular definitions are detected */
936                                                 for (affecting_node = defined_slot->used_locals; affecting_node != NULL; affecting_node = affecting_node->next_used_local) {
937                                                         tree_mover_link_affecting_node (affecting_node, defined_slot);
938                                                 }
939                                         } else if (MONO_DEBUG_TREE_MOVER) {
940                                                 /* otherwise, do nothing */
941                                                 printf ("Skipping definition of slot %d by tree: ", defined_index);
942                                                 mono_print_tree_nl (tree);
943                                         }
944                                 } else {
945                                         TreeMoverDependencyFromDeadDefinition *dependency;
946                                         /* forwarding previous definition: */
947                                         if (MONO_DEBUG_TREE_MOVER) {
948                                                 printf ("Handling forwarding in slot %d for tree: ", defined_index);
949                                                 mono_print_tree_nl (tree);
950                                         }
951                                         /* Setup slot for forwarding */
952                                         defined_slot->pending_move = forwarding_source->pending_move;
953                                         defined_slot->pending_move_is_forwarded = TRUE;
954                                         /* Setup forwarding dependency node */
955                                         dependency = mono_mempool_alloc0 (tree_mover->pool, sizeof (TreeMoverDependencyFromDeadDefinition));
956                                         dependency->defined_slot = defined_slot;
957                                         dependency->dead_definition = tree;
958                                         dependency->next = defined_slot->pending_move->slots_that_must_be_safe;
959                                         defined_slot->pending_move->slots_that_must_be_safe = dependency;
960                                         /* Clear use (put slot back to state [D]) */
961                                         defined_slot->pending_move->use = NULL;
962                                         defined_slot->pending_move->defined_slot->pending_move_is_ready = FALSE;
963                                 }
964
965                                 /* Then kill all affected definitions waiting for a use */
966                                 affected_node = defined_slot->affected_locals;
967                                 while (affected_node != NULL) {
968                                         TreeMoverDependencyNode *next_affected_node = affected_node->next_affected_local;
969                                         TreeMoverActSlot *affected_slot = affected_node->affected_slot;
970                                         
971                                         if (affected_node->use_is_direct) {
972                                                 /* Direct use: kill affected slot */
973                                                 if (MONO_DEBUG_TREE_MOVER) {
974                                                         printf ("  Direct use, killing slot %d with definition:", tree_mover_slot_to_index (tree_mover, affected_node->affected_slot));
975                                                         mono_print_tree_nl (affected_slot->pending_move->definition);
976                                                 }
977                                                 tree_mover_kill_act_slot_because_it_is_affected (tree_mover, affected_slot);
978                                         } else if ((defined_slot->pending_move!= NULL) &&
979                                                         (! defined_slot->pending_move_is_ready) &&
980                                                         (! defined_slot->pending_move_is_forwarded) &&
981                                                         (affected_slot->pending_move!= NULL) &&
982                                                         (! affected_slot->pending_move_is_ready) &&
983                                                         (! affected_slot->pending_move_is_forwarded)) {
984                                                 if (MONO_DEBUG_TREE_MOVER) {
985                                                         printf ("  Indirect use, linking slots %d and %d\n", tree_mover_slot_to_index (tree_mover, affected_node->used_slot), tree_mover_slot_to_index (tree_mover, affected_node->affected_slot));
986                                                 }
987                                                 tree_mover_link_affected_moves (tree_mover, defined_slot, affected_slot);
988                                                 tree_mover_link_affected_moves (tree_mover, affected_slot, defined_slot);
989                                         }
990                                         tree_mover_unlink_affecting_node (affected_node);
991                                         
992                                         if ((next_affected_node != NULL) && (next_affected_node->affected_slot != NULL)) {
993                                                 affected_node = next_affected_node;
994                                         } else {
995                                                 affected_node = defined_slot->affected_locals;
996                                         }
997                                 }
998                                 if (MONO_DUMP_TREE_MOVER) {
999                                         tree_mover_print_act_slot ("DEFINITION", tree_mover, defined_slot);
1000                                 }
1001                         }
1002                 }
1003
1004                 /* After we are done with this tree, clear the tree mover area */
1005                 if ((tree_mover != NULL) && (tree_mover->used_nodes != NULL)) {
1006                         tree_mover_dispose_used_nodes (tree_mover);
1007                 }
1008
1009                 /*
1010                   if (tree->opcode == CEE_BEQ) {
1011                   g_assert (tree->inst_i0->opcode == OP_COMPARE);
1012                   if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
1013                   tree->inst_i0->inst_i1->opcode == OP_ICONST) {
1014
1015                   tree->opcode = OP_BR;
1016                   if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
1017                   tree->inst_target_bb = tree->inst_true_bb;
1018                   } else {
1019                   tree->inst_target_bb = tree->inst_false_bb;
1020                   }
1021                   }
1022                   }
1023                 */
1024         }
1025         
1026         if (tree_mover != NULL) {
1027                 /* At BB end, kill all definitions still waiting for a use */
1028                 tree_mover_clear_act_recording_moves (tree_mover, acp_size);
1029                 if (MONO_DEBUG_TREE_MOVER) {
1030                         tree_mover_verify_dependency_nodes_are_clear (tree_mover, acp_size);
1031                 }
1032         }
1033 }
1034
1035
1036 #if (MONO_APPLY_TREE_MOVER_TO_SINGLE_METHOD)
1037 static char*
1038 mono_tree_mover_method_name = NULL;
1039 static gboolean check_tree_mover_method_name (MonoCompile *cfg) {
1040         if (mono_tree_mover_method_name == NULL) {
1041                 mono_tree_mover_method_name = getenv ("MONO_TREE_MOVER_METHOD_NAME");
1042         }
1043         if (mono_tree_mover_method_name != NULL) {
1044                 char *method_name = mono_method_full_name (cfg->method, TRUE);
1045                 if (strstr (method_name, mono_tree_mover_method_name) != NULL) {
1046                         g_free (method_name);
1047                         return TRUE;
1048                 } else {
1049                         g_free (method_name);
1050                         return FALSE;
1051                 }
1052         } else {
1053                 return TRUE;
1054         }
1055 }
1056 #endif
1057
1058 #if (MONO_APPLY_TREE_MOVER_TO_COUNTED_METHODS)
1059 static int
1060 mono_tree_mover_method_limit = -1;
1061 static int
1062 mono_tree_mover_method_count = 0;
1063 static gboolean check_tree_mover_method_count (MonoCompile *cfg) {
1064         if (mono_tree_mover_method_limit == -1) {
1065                 char *limit_string = getenv ("MONO_TREE_MOVER_METHOD_LIMIT");
1066                 if (limit_string != NULL) {
1067                         mono_tree_mover_method_limit = atoi (limit_string);
1068                 } else {
1069                         mono_tree_mover_method_limit = -2;
1070                 }
1071         }
1072         if (mono_tree_mover_method_limit > -1) {
1073                 mono_tree_mover_method_count ++;
1074                 if (mono_tree_mover_method_count == mono_tree_mover_method_limit) {
1075                         char *method_name = mono_method_full_name (cfg->method, TRUE);
1076                         printf ("Last method compiled with treeprop: %s\n", method_name);
1077                         g_free (method_name);
1078                         
1079                 }
1080                 return (mono_tree_mover_method_count <= mono_tree_mover_method_limit);
1081         } else {
1082                 return TRUE;
1083         }
1084 }
1085 #endif
1086
1087 static void
1088 apply_tree_mover (TreeMover *tree_mover, TreeMoverTreeMove *move) {
1089         TreeMoverDependencyFromDeadDefinition *dependency;
1090         TreeMoverAffectedMove *affected_move;
1091
1092         /* Test if this move has been explicitly disabled */
1093         if (move->skip_this_move) {
1094                 if (MONO_DEBUG_TREE_MOVER) {
1095                         printf ("Move of slot %d must be skipped: ", tree_mover_slot_to_index (tree_mover, move->defined_slot));
1096                         mono_print_tree_nl (move->definition);
1097                 }
1098                 return;
1099         }
1100         /* Test if this move is safe */
1101         if ((! move->move_is_safe) && move->defined_slot->unsafe_flag) {
1102                 if (MONO_DEBUG_TREE_MOVER) {
1103                         printf ("Move of slot %d is unsafe: ", tree_mover_slot_to_index (tree_mover, move->defined_slot));
1104                         mono_print_tree_nl (move->definition);
1105                 }
1106                 return;
1107         }
1108         /* Test if this move depends from a definition that should have been dead */
1109         for (dependency = move->slots_that_must_be_safe; dependency != NULL; dependency = dependency->next) {
1110                 if ((dependency->defined_slot != NULL) && dependency->defined_slot->unsafe_flag) {
1111                         if (MONO_DEBUG_TREE_MOVER) {
1112                                 printf ("Move of slot %d depended from unsafe slot %d: ", tree_mover_slot_to_index (tree_mover, move->defined_slot), tree_mover_slot_to_index (tree_mover, dependency->defined_slot));
1113                                 mono_print_tree_nl (move->definition);
1114                         }
1115                         return;
1116                 }
1117         }
1118
1119         if (MONO_DEBUG_TREE_MOVER) {
1120                 printf ("Performing move of slot %d: ", tree_mover_slot_to_index (tree_mover, move->defined_slot));
1121                 mono_print_tree_nl (move->definition);
1122         }
1123         /* All tests passed, apply move */
1124         *(move->use) = move->definition->inst_i1;
1125         move->definition->opcode = OP_NOP;
1126         move->definition->ssa_op = MONO_SSA_NOP;
1127
1128         /* Then disable moves affected by this move */
1129         affected_move = move->affected_moves;
1130         while (affected_move != NULL) {
1131                 if (MONO_DEBUG_TREE_MOVER) {
1132                         printf ("  Consequently, disabling slot %d\n", tree_mover_slot_to_index (tree_mover, affected_move->affected_move->defined_slot));
1133                 }
1134                 affected_move->affected_move->skip_this_move = TRUE;
1135                 affected_move = affected_move->next_affected_move;
1136         }
1137
1138         /* Also kill dead dependency definitions */
1139         for (dependency = move->slots_that_must_be_safe; dependency != NULL; dependency = dependency->next) {
1140                 if (dependency->defined_slot != NULL) {
1141                         if (MONO_DEBUG_TREE_MOVER) {
1142                                 printf ("  Consequently, kill dependent definition %d: ", tree_mover_slot_to_index (tree_mover, dependency->defined_slot));
1143                                 mono_print_tree_nl (dependency->dead_definition);
1144                         }
1145                         dependency->dead_definition->opcode = OP_NOP;
1146                         dependency->dead_definition->ssa_op = MONO_SSA_NOP;
1147                 }
1148         }
1149 }
1150
1151 void
1152 mono_local_cprop (MonoCompile *cfg) {
1153         MonoBasicBlock *bb;
1154         MonoInst **acp;
1155         TreeMover *tree_mover;
1156
1157         acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
1158         
1159         if (cfg->opt & MONO_OPT_TREEPROP) {
1160                 MonoMemPool *pool = mono_mempool_new();
1161                 tree_mover = mono_mempool_alloc0(pool, sizeof (TreeMover));
1162                 
1163                 tree_mover->cfg = cfg;
1164                 tree_mover->pool = pool;
1165                 tree_mover->ACT = mono_mempool_alloc0 (pool, sizeof (TreeMoverActSlot) * (cfg->num_varinfo));           
1166 #if (MONO_APPLY_TREE_MOVER_TO_SINGLE_METHOD)
1167                 if (! check_tree_mover_method_name (cfg)) {
1168                         mono_mempool_destroy(tree_mover->pool);
1169                         tree_mover = NULL;
1170                 }
1171 #endif
1172 #if (MONO_APPLY_TREE_MOVER_TO_COUNTED_METHODS)
1173                 if (! check_tree_mover_method_count (cfg)) {
1174                         mono_mempool_destroy(tree_mover->pool);
1175                         tree_mover = NULL;
1176                 }
1177 #endif
1178         } else {
1179                 tree_mover = NULL;
1180         }
1181
1182         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1183                 if (MONO_DEBUG_LOCAL_PROP||MONO_DEBUG_TREE_MOVER) {
1184                         printf ("Applying mono_local_cprop to BB%d\n", bb->block_num);
1185                 }
1186                 memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
1187                 mono_local_cprop_bb (cfg, tree_mover, bb, acp, cfg->num_varinfo);
1188         }
1189         
1190         if (tree_mover != NULL) {
1191                 TreeMoverTreeMove *move;
1192                 /* Move the movable trees */
1193                 if (MONO_DEBUG_TREE_MOVER) {
1194                         printf ("BEFORE TREE MOVER START\n");
1195                         mono_print_code (cfg);
1196                         printf ("BEFORE TREE MOVER END\n");
1197                         printf ("Applying tree mover...\n");
1198                 }
1199                 for (move = tree_mover->scheduled_moves; move != NULL; move = move->next) {
1200                         apply_tree_mover (tree_mover, move);
1201                 }
1202                 if (MONO_DEBUG_TREE_MOVER) {
1203                         printf ("AFTER TREE MOVER START\n");
1204                         mono_print_code (cfg);
1205                         printf ("AFTER TREE MOVER END\n");
1206                 }
1207                 
1208                 /* Global cleanup of tree mover memory */
1209                 mono_mempool_destroy(tree_mover->pool);
1210         }
1211 }