2 * ssapre.h: SSA Partial Redundancy Elimination
5 * Massimiliano Mantione (massi@ximian.com)
7 * (C) 2004 Novell, Inc. http://www.novell.com
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/metadata/opcodes.h>
24 /* Disable for now to save space since it is not yet ported to linear IR */
29 /* Logging conditions */
30 #define DUMP_LEVEL (4)
31 #define TRACE_LEVEL (3)
32 #define STATISTICS_LEVEL (2)
34 #define DUMP_SSAPRE (area->cfg->verbose_level >= DUMP_LEVEL)
35 #define TRACE_SSAPRE (area->cfg->verbose_level >= TRACE_LEVEL)
36 #define STATISTICS_SSAPRE (area->cfg->verbose_level >= STATISTICS_LEVEL)
37 #define LOG_SSAPRE (area->cfg->verbose_level >= LOG_LEVEL)
39 /* "Bottom" symbol definition (see paper) */
40 #define BOTTOM_REDUNDANCY_CLASS (-1)
42 /* Various printing functions... */
44 print_argument (MonoSsapreExpressionArgument
*argument
) {
45 switch (argument
->type
) {
46 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
:
49 case MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT
:
52 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE
:
53 printf ("ORIGINAL_VARIABLE %d", argument
->argument
.original_variable
);
55 case MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
:
56 printf ("SSA_VARIABLE %d", argument
->argument
.ssa_variable
);
58 case MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT
:
59 printf ("INTEGER_CONSTANT %d", argument
->argument
.integer_constant
);
61 case MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT
:
62 printf ("LONG_COSTANT %lld", (long long)*(argument
->argument
.long_constant
));
64 case MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT
:
65 printf ("FLOAT_COSTANT %f", *(argument
->argument
.float_constant
));
67 case MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT
:
68 printf ("DOUBLE_COSTANT %f", *(argument
->argument
.double_constant
));
71 printf ("UNKNOWN: %d", argument
->type
);
77 print_expression_description (MonoSsapreExpressionDescription
*expression_description
) {
78 if (expression_description
->opcode
!= 0) {
79 printf ("%s ([", mono_inst_name (expression_description
->opcode
) );
80 print_argument (&(expression_description
->left_argument
));
82 print_argument (&(expression_description
->right_argument
));
89 #if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
91 snprint_argument (GString
*string
, MonoSsapreExpressionArgument
*argument
) {
92 switch (argument
->type
) {
93 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
:
94 g_string_append_printf (string
, "ANY");
96 case MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT
:
97 g_string_append_printf (string
, "NONE");
99 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE
:
100 g_string_append_printf (string
, "ORIGINAL_VARIABLE %d", argument
->argument
.original_variable
);
102 case MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
:
103 g_string_append_printf (string
, "SSA_VARIABLE %d", argument
->argument
.ssa_variable
);
105 case MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT
:
106 g_string_append_printf (string
, "INTEGER_CONSTANT %d", argument
->argument
.integer_constant
);
108 case MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT
:
109 g_string_append_printf (string
, "LONG_COSTANT %lld", *(argument
->argument
.long_constant
));
111 case MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT
:
112 g_string_append_printf (string
, "FLOAT_COSTANT %f", *(argument
->argument
.float_constant
));
114 case MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT
:
115 g_string_append_printf (string
, "DOUBLE_COSTANT %f", *(argument
->argument
.double_constant
));
118 g_string_append_printf (string
, "UNKNOWN: %d", argument
->type
);
123 snprint_expression_description (GString
*string
, MonoSsapreExpressionDescription
*expression_description
) {
124 if (expression_description
->opcode
!= 0) {
125 g_string_append_printf (string
, "%s ([", mono_inst_name (expression_description
->opcode
) );
126 snprint_argument (string
, &(expression_description
->left_argument
));
127 g_string_append_printf (string
, "],[");
128 snprint_argument (string
, &(expression_description
->right_argument
));
129 g_string_append_printf (string
, "])");
131 g_string_append_printf (string
, "ANY");
136 #define GBOOLEAN_TO_STRING(b) ((b)?"TRUE":"FALSE")
139 print_expression_occurrence (MonoSsapreExpressionOccurrence
*occurrence
, int number
) {
140 printf (" ([%d][bb %d [ID %d]][class %d]: ", number
, occurrence
->bb_info
->cfg_dfn
, occurrence
->bb_info
->bb
->block_num
, occurrence
->redundancy_class
);
141 print_expression_description (&(occurrence
->description
));
142 if (occurrence
->is_first_in_bb
) {
143 printf (" [FIRST in BB]");
145 if (occurrence
->is_last_in_bb
) {
146 printf (" [LAST in BB]");
148 printf (" (save = %s)", GBOOLEAN_TO_STRING (occurrence
->save
));
149 printf (" (reload = %s)", GBOOLEAN_TO_STRING (occurrence
->reload
));
151 occurrence
= occurrence
->next
;
155 print_expression_occurrences (MonoSsapreExpressionOccurrence
*occurrences
) {
157 while (occurrences
!= NULL
) {
159 print_expression_occurrence (occurrences
, i
);
160 occurrences
= occurrences
->next
;
165 print_worklist (MonoSsapreExpression
*expression
) {
166 if (expression
!= NULL
) {
167 print_worklist (expression
->previous
);
169 printf ("{%d}: ", expression
->tree_size
);
170 print_expression_description (&(expression
->description
));
172 print_expression_occurrences (expression
->occurrences
);
174 print_worklist (expression
->next
);
179 print_bb_info (MonoSsapreBBInfo
*bb_info
, gboolean print_occurrences
) {
181 MonoSsapreExpressionOccurrence
*current_occurrence
= bb_info
->first_expression_in_bb
;
183 printf ("bb %d [ID %d]: IN { ", bb_info
->cfg_dfn
, bb_info
->bb
->block_num
);
184 for (i
= 0; i
< bb_info
->in_count
; i
++) {
185 printf ("%d [ID %d] ", bb_info
->in_bb
[i
]->cfg_dfn
, bb_info
->in_bb
[i
]->bb
->block_num
);
188 for (i
= 0; i
< bb_info
->out_count
; i
++) {
189 printf ("%d [ID %d] ", bb_info
->out_bb
[i
]->cfg_dfn
, bb_info
->out_bb
[i
]->bb
->block_num
);
192 if (bb_info
->next_interesting_bb
!= NULL
) {
193 printf (", NEXT %d [ID %d]", bb_info
->next_interesting_bb
->cfg_dfn
, bb_info
->next_interesting_bb
->bb
->block_num
);
195 if (bb_info
->dt_covered_by_interesting_BBs
) {
196 printf (" (COVERED)");
198 printf (" (NEVER DOWN SAFE)");
201 if (bb_info
->has_phi
) {
202 printf (" PHI, class %d [ ", bb_info
->phi_redundancy_class
);
203 for (i
= 0; i
< bb_info
->in_count
; i
++) {
204 int argument_class
= bb_info
->phi_arguments_classes
[i
];
205 if (argument_class
!= BOTTOM_REDUNDANCY_CLASS
) {
206 printf ("%d ", argument_class
);
211 printf ("]\n(phi_defines_a_real_occurrence:%s) (phi_is_down_safe:%s) (phi_can_be_available:%s) (phi_is_later:%s)\n",
212 GBOOLEAN_TO_STRING (bb_info
->phi_defines_a_real_occurrence
), GBOOLEAN_TO_STRING (bb_info
->phi_is_down_safe
),
213 GBOOLEAN_TO_STRING (bb_info
->phi_can_be_available
), GBOOLEAN_TO_STRING (bb_info
->phi_is_later
));
215 if (print_occurrences
) {
217 while ((current_occurrence
!= NULL
) && (current_occurrence
->bb_info
== bb_info
)) {
218 print_expression_occurrence (current_occurrence
, i
);
219 current_occurrence
= current_occurrence
->next
;
223 if (bb_info
->has_phi_argument
) {
224 printf (" PHI ARGUMENT, class ");
225 if (bb_info
->phi_argument_class
!= BOTTOM_REDUNDANCY_CLASS
) {
226 printf ("%d ", bb_info
->phi_argument_class
);
230 if (bb_info
->phi_argument_defined_by_real_occurrence
!= NULL
) {
231 printf ("(Defined by real occurrence %d)", bb_info
->phi_argument_defined_by_real_occurrence
->redundancy_class
);
232 } else if (bb_info
->phi_argument_defined_by_phi
!= NULL
) {
233 printf ("(Defined by phi %d)", bb_info
->phi_argument_defined_by_phi
->phi_redundancy_class
);
235 printf ("(Undefined)");
237 printf (" (real occurrence arguments: left ");
238 if (bb_info
->phi_argument_left_argument_version
!= BOTTOM_REDUNDANCY_CLASS
) {
239 printf ("%d ", bb_info
->phi_argument_left_argument_version
);
244 if (bb_info
->phi_argument_right_argument_version
!= BOTTOM_REDUNDANCY_CLASS
) {
245 printf ("%d ", bb_info
->phi_argument_right_argument_version
);
249 printf (")\n(phi_argument_has_real_use:%s) (phi_argument_needs_insert:%s) (phi_argument_has_been_processed:%s)\n",
250 GBOOLEAN_TO_STRING (bb_info
->phi_argument_has_real_use
), GBOOLEAN_TO_STRING (bb_info
->phi_argument_needs_insert
),
251 GBOOLEAN_TO_STRING (bb_info
->phi_argument_has_been_processed
));
256 print_bb_infos (MonoSsapreWorkArea
*area
) {
258 for (i
= 0; i
< area
->num_bblocks
; i
++) {
259 MonoSsapreBBInfo
*bb_info
= &(area
->bb_infos
[i
]);
260 print_bb_info (bb_info
, TRUE
);
265 print_interesting_bb_infos (MonoSsapreWorkArea
*area
) {
266 MonoSsapreBBInfo
*current_bb
;
268 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
269 print_bb_info (current_bb
, FALSE
);
273 static void dump_code (MonoSsapreWorkArea
*area
) {
276 for (i
= 0; i
< area
->num_bblocks
; i
++) {
277 MonoSsapreBBInfo
*current_bb
= &(area
->bb_infos
[i
]);
278 MonoInst
*current_inst
;
280 print_bb_info (current_bb
, TRUE
);
281 MONO_BB_FOR_EACH_INS (current_bb
->bb
, current_inst
)
282 mono_print_tree_nl (current_inst
);
287 * Given a MonoInst, it tries to describe it as an expression argument.
288 * If this is not possible, the result will be of type
289 * MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY.
292 analyze_argument (MonoInst
*argument
, MonoSsapreExpressionArgument
*result
) {
293 switch (argument
->opcode
) {
305 if ((argument
->inst_left
->opcode
== OP_LOCAL
) || (argument
->inst_left
->opcode
== OP_ARG
)) {
306 result
->type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
;
307 result
->argument
.ssa_variable
= argument
->inst_left
->inst_c0
;
309 result
->type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
;
313 result
->type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT
;
314 result
->argument
.integer_constant
= argument
->inst_c0
;
317 result
->type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT
;
318 result
->argument
.long_constant
= &(argument
->inst_l
);
321 if (! isnan (*((float*)argument
->inst_p0
))) {
322 result
->type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT
;
323 result
->argument
.float_constant
= (float*)argument
->inst_p0
;
325 result
->type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
;
329 if (! isnan (*((double*)argument
->inst_p0
))) {
330 result
->type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT
;
331 result
->argument
.double_constant
= (double*)argument
->inst_p0
;
333 result
->type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
;
337 result
->type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
;
343 * Given a MonoInst, it tries to describe it as an expression.
344 * If this is not possible, the result will have opcode 0.
347 analyze_expression (MonoInst
*expression
, MonoSsapreExpressionDescription
*result
) {
348 switch (expression
->opcode
) {
349 #define SSAPRE_SPECIFIC_OPS 1
350 #define OPDEF(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) case a1:
351 #include "simple-cee-ops.h"
353 #define MINI_OP(a1,a2) case a1:
354 #include "simple-mini-ops.h"
356 #undef SSAPRE_SPECIFIC_OPS
357 if ( (expression
->type
== STACK_I4
) ||
358 (expression
->type
== STACK_PTR
) ||
359 (expression
->type
== STACK_MP
) ||
360 (expression
->type
== STACK_I8
) ||
361 (expression
->type
== STACK_R8
) ) {
362 if (mono_burg_arity
[expression
->opcode
] > 0) {
363 result
->opcode
= expression
->opcode
;
364 analyze_argument (expression
->inst_left
, &(result
->left_argument
));
365 if (mono_burg_arity
[expression
->opcode
] > 1) {
366 analyze_argument (expression
->inst_right
, &(result
->right_argument
));
368 result
->right_argument
.type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT
;
375 //~ if (expression->type != 0) {
376 //~ MonoType *type = mono_type_from_stack_type (expression);
377 //~ printf ("SSAPRE refuses opcode %s (%d) with type %s (%d)\n", mono_inst_name (expression->opcode), expression->opcode, mono_type_full_name (type), expression->type);
379 //~ printf ("SSAPRE cannot really handle expression of opcode %s (%d)\n", mono_inst_name (expression->opcode), expression->opcode);
385 result
->left_argument
.type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
;
386 result
->right_argument
.type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
;
388 //~ switch (expression->opcode) {
390 //~ if ((result->left_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT) &&
391 //~ (result->right_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT)) {
394 //~ case CEE_LDELEMA:
396 //~ result->opcode = 0;
397 //~ result->left_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
398 //~ result->right_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
403 * Given an expression description, if any of its arguments has type
404 * MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE it transforms it to a
405 * MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE, converting the
406 * variable index to its "original" one.
407 * The resulting description is OK for a "MonoSsapreExpression" (the
408 * initial description came from a "MonoSsapreExpressionOccurrence").
411 convert_ssa_variables_to_original_names (MonoSsapreExpressionDescription
*result
, MonoSsapreExpressionDescription
*expression
, MonoCompile
*cfg
) {
412 gssize original_variable
;
414 result
->opcode
= expression
->opcode
;
415 if (expression
->left_argument
.type
!= MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
) {
416 result
->left_argument
= expression
->left_argument
;
418 result
->left_argument
.type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE
;
419 original_variable
= MONO_VARINFO (cfg
, expression
->left_argument
.argument
.ssa_variable
)->reg
;
420 if (original_variable
>= 0) {
421 result
->left_argument
.argument
.original_variable
= original_variable
;
423 result
->left_argument
.argument
.original_variable
= expression
->left_argument
.argument
.ssa_variable
;
426 if (expression
->right_argument
.type
!= MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
) {
427 result
->right_argument
= expression
->right_argument
;
429 result
->right_argument
.type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE
;
430 original_variable
= MONO_VARINFO (cfg
, expression
->right_argument
.argument
.ssa_variable
)->reg
;
431 if (original_variable
>= 0) {
432 result
->right_argument
.argument
.original_variable
= original_variable
;
434 result
->right_argument
.argument
.original_variable
= expression
->right_argument
.argument
.ssa_variable
;
440 * Given a MonoInst, checks if it is a phi definition.
443 is_phi_definition (MonoInst
*definition
) {
444 if (definition
!= NULL
) {
445 switch (definition
->opcode
) {
454 if ((definition
->inst_left
->opcode
== OP_LOCAL
) &&
455 (definition
->inst_right
->opcode
== OP_PHI
)) {
469 * Given a variable index, checks if it is a phi definition
470 * (it assumes the "area" is visible).
472 #define IS_PHI_DEFINITION(v) is_phi_definition (MONO_VARINFO (area->cfg, v)->def)
475 * Given a variable index, checks if it is a phi definition.
476 * If it is so, it returns the array of integers pointed to by the phi MonoInst
477 * (the one containing the length and the phi arguments), otherwise returns NULL.
480 get_phi_definition (MonoCompile
*cfg
, gssize variable
) {
481 MonoInst
*definition
= MONO_VARINFO (cfg
, variable
)->def
;
482 if (is_phi_definition (definition
) && (definition
->inst_left
->inst_c0
== variable
)) {
483 return definition
->inst_right
->inst_phi_args
;
490 * Given a variable index, returns the BB where the variable is defined.
491 * If the variable appears to have no definition, it returns the entry BB
492 * (the logic is that if it has no definition it is an argument, or a sort
493 * of constant, and in both cases it is defined in the entry BB).
495 static MonoSsapreBBInfo
*
496 get_bb_info_of_definition (MonoSsapreWorkArea
*area
, gssize variable
) {
497 MonoBasicBlock
*def_bb
= MONO_VARINFO (area
->cfg
, variable
)->def_bb
;
498 if (def_bb
!= NULL
) {
499 return area
->bb_infos_in_cfg_dfn_order
[def_bb
->dfn
];
501 return area
->bb_infos
;
507 * - a variable index,
508 * - a BB (the "current" BB), and
509 * - a "phi argument index" (or index in the "in_bb" of the current BB),
510 * it checks if the variable is a phi.
511 * If it is so, it returns the variable index at the in_bb corresponding to
512 * the given index, otherwise it return the variable index unchanged.
513 * The logic is to return the variable version at the given predecessor BB.
516 get_variable_version_at_predecessor_bb (MonoSsapreWorkArea
*area
, gssize variable
, MonoSsapreBBInfo
*current_bb
, int phi_operand
) {
517 MonoSsapreBBInfo
*definition_bb
= get_bb_info_of_definition (area
, variable
);
518 int *phi_definition
= get_phi_definition (area
->cfg
, variable
);
519 if ((definition_bb
== current_bb
) && (phi_definition
!= NULL
)) {
520 return phi_definition
[phi_operand
+ 1];
527 * Adds an expression to an autobalancing binary tree of expressions.
528 * Returns the new tree root (it can be different from "tree" because of the
531 static MonoSsapreExpression
*
532 add_expression_to_tree (MonoSsapreExpression
*tree
, MonoSsapreExpression
*expression
) {
533 MonoSsapreExpression
*subtree
;
534 MonoSsapreExpression
**subtree_reference
;
536 gssize max_tree_depth
, max_subtree_size
;
539 expression
->previous
= NULL
;
540 expression
->next
= NULL
;
541 expression
->tree_size
= 1;
547 comparison
= MONO_COMPARE_SSAPRE_EXPRESSION_DESCRIPTIONS (expression
->description
, tree
->description
);
548 if (comparison
> 0) {
549 if (tree
->next
!= NULL
) {
550 subtree
= tree
->next
;
551 subtree_reference
= &(tree
->next
);
553 tree
->next
= expression
;
554 expression
->father
= tree
;
555 expression
->previous
= NULL
;
556 expression
->next
= NULL
;
557 expression
->tree_size
= 1;
560 } else if (comparison
< 0) {
561 if (tree
->previous
!= NULL
) {
562 subtree
= tree
->previous
;
563 subtree_reference
= &(tree
->previous
);
565 tree
->previous
= expression
;
566 expression
->father
= tree
;
567 expression
->previous
= NULL
;
568 expression
->next
= NULL
;
569 expression
->tree_size
= 1;
573 g_assert_not_reached ();
577 MONO_SSAPRE_MAX_TREE_DEPTH (tree
->tree_size
, max_tree_depth
);
578 max_subtree_size
= (1 << max_tree_depth
) -1;
580 if (subtree
->tree_size
< max_subtree_size
) {
581 *subtree_reference
= add_expression_to_tree (subtree
, expression
);
582 (*subtree_reference
)->father
= tree
;
585 MonoSsapreExpression
*other_subtree
;
586 MonoSsapreExpression
*border_expression
;
587 MonoSsapreExpression
*border_expression_subtree
;
588 MonoSsapreExpression
**border_expression_reference_from_father
;
589 int comparison_with_border
;
591 border_expression
= subtree
;
592 if (comparison
> 0) {
593 other_subtree
= tree
->previous
;
594 MONO_SSAPRE_GOTO_FIRST_EXPRESSION (border_expression
);
595 border_expression_subtree
= border_expression
->next
;
596 border_expression_reference_from_father
= &(border_expression
->father
->previous
);
597 } else if (comparison
< 0) {
598 other_subtree
= tree
->next
;
599 MONO_SSAPRE_GOTO_LAST_EXPRESSION (border_expression
);
600 border_expression_subtree
= border_expression
->previous
;
601 border_expression_reference_from_father
= &(border_expression
->father
->next
);
603 g_assert_not_reached ();
606 comparison_with_border
= MONO_COMPARE_SSAPRE_EXPRESSION_DESCRIPTIONS (expression
->description
, border_expression
->description
);
608 if ((comparison
+ comparison_with_border
) != 0) {
609 MonoSsapreExpression
*border_expression_iterator
= border_expression
->father
;
610 while (border_expression_iterator
!= tree
) {
611 border_expression_iterator
->tree_size
--;
612 border_expression_iterator
= border_expression_iterator
->father
;
615 if (border_expression
!= subtree
) {
616 *border_expression_reference_from_father
= border_expression_subtree
;
618 subtree
= border_expression_subtree
;
620 if (border_expression_subtree
!= NULL
) {
621 border_expression_subtree
->father
= border_expression
->father
;
624 if (comparison
> 0) {
625 border_expression
->previous
= add_expression_to_tree (other_subtree
, tree
);
626 border_expression
->next
= add_expression_to_tree (subtree
, expression
);
627 } else if (comparison
< 0) {
628 border_expression
->previous
= add_expression_to_tree (subtree
, expression
);
629 border_expression
->next
= add_expression_to_tree (other_subtree
, tree
);
631 g_assert_not_reached ();
634 border_expression
->tree_size
= 1 + border_expression
->previous
->tree_size
+ border_expression
->next
->tree_size
;
635 return border_expression
;
637 if (comparison
> 0) {
638 expression
->previous
= add_expression_to_tree (other_subtree
, tree
);
639 expression
->next
= subtree
;
640 } else if (comparison
< 0) {
641 expression
->previous
= subtree
;
642 expression
->next
= add_expression_to_tree (other_subtree
, tree
);
644 g_assert_not_reached ();
647 expression
->tree_size
= 1 + expression
->previous
->tree_size
+ expression
->next
->tree_size
;
653 #if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
654 static char *mono_ssapre_expression_name
= NULL
;
656 check_ssapre_expression_name (MonoSsapreWorkArea
*area
, MonoSsapreExpressionDescription
*expression_description
) {
657 if (area
->expression_is_handled_father
) {
660 if (mono_ssapre_expression_name
== NULL
) {
661 mono_ssapre_expression_name
= getenv ("MONO_SSAPRE_EXPRESSION_NAME");
663 if (mono_ssapre_expression_name
!= NULL
) {
664 GString
*expression_name
= g_string_new_len ("", 256);
665 gboolean return_value
;
666 snprint_expression_description (expression_name
, expression_description
);
667 if (strstr (expression_name
->str
, mono_ssapre_expression_name
) != NULL
) {
670 return_value
= FALSE
;
672 g_string_free (expression_name
, TRUE
);
681 * Adds an expression to the worklist (putting the current occurrence as first
682 * occurrence of this expression).
685 add_expression_to_worklist (MonoSsapreWorkArea
*area
) {
686 MonoSsapreExpressionOccurrence
*occurrence
= area
->current_occurrence
;
687 MonoSsapreExpression
*expression
= (MonoSsapreExpression
*) mono_mempool_alloc (area
->mempool
, sizeof (MonoSsapreExpression
));
689 convert_ssa_variables_to_original_names (&(expression
->description
), &(occurrence
->description
), area
->cfg
);
691 #if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
692 if (! check_ssapre_expression_name (area
, &(expression
->description
))) return;
695 expression
->type
= mono_type_from_stack_type (occurrence
->occurrence
);
696 expression
->occurrences
= NULL
;
697 expression
->last_occurrence
= NULL
;
698 expression
->next_in_queue
= NULL
;
699 if (area
->last_in_queue
!= NULL
) {
700 area
->last_in_queue
->next_in_queue
= expression
;
702 area
->first_in_queue
= expression
;
704 area
->last_in_queue
= expression
;
705 MONO_SSAPRE_ADD_EXPRESSION_OCCURRANCE (expression
, occurrence
);
707 area
->worklist
= add_expression_to_tree (area
->worklist
, expression
);
708 area
->worklist
->father
= NULL
;
712 * Adds the current expression occurrence to the worklist.
713 * If its expression is not yet in the worklist, it is created.
716 add_occurrence_to_worklist (MonoSsapreWorkArea
*area
) {
717 MonoSsapreExpressionDescription description
;
718 MonoSsapreExpression
*current_expression
;
721 convert_ssa_variables_to_original_names (&description
, &(area
->current_occurrence
->description
), area
->cfg
);
722 current_expression
= area
->worklist
;
725 if (current_expression
!= NULL
) {
726 comparison
= MONO_COMPARE_SSAPRE_EXPRESSION_DESCRIPTIONS (description
, current_expression
->description
);
728 if (comparison
> 0) {
729 current_expression
= current_expression
->next
;
730 } else if (comparison
< 0) {
731 current_expression
= current_expression
->previous
;
733 MONO_SSAPRE_ADD_EXPRESSION_OCCURRANCE (current_expression
, area
->current_occurrence
);
736 add_expression_to_worklist (area
);
739 } while (comparison
!= 0);
741 area
->current_occurrence
= (MonoSsapreExpressionOccurrence
*) mono_mempool_alloc (area
->mempool
, sizeof (MonoSsapreExpressionOccurrence
));
745 * Process a MonoInst, and of it is a valid expression add it to the worklist.
748 process_inst (MonoSsapreWorkArea
*area
, MonoInst
* inst
, MonoInst
* previous_inst
, MonoSsapreFatherExpression
*** father_in_tree
, MonoSsapreBBInfo
*bb_info
) {
749 MonoSsapreFatherExpression
** left_father_in_tree
= NULL
;
750 MonoSsapreFatherExpression
** right_father_in_tree
= NULL
;
752 if (mono_burg_arity
[inst
->opcode
] > 0) {
753 process_inst (area
, inst
->inst_left
, previous_inst
, &left_father_in_tree
, bb_info
);
754 if (mono_burg_arity
[inst
->opcode
] > 1) {
755 process_inst (area
, inst
->inst_right
, previous_inst
, &right_father_in_tree
, bb_info
);
759 analyze_expression (inst
, &(area
->current_occurrence
->description
));
760 if (area
->current_occurrence
->description
.opcode
!= 0) {
761 if ((left_father_in_tree
!= NULL
) || (right_father_in_tree
!= NULL
)) {
762 MonoSsapreFatherExpression
*current_inst_as_father
= (MonoSsapreFatherExpression
*) mono_mempool_alloc (area
->mempool
, sizeof (MonoSsapreFatherExpression
));
763 current_inst_as_father
->father_occurrence
= inst
;
764 current_inst_as_father
->grand_father
= NULL
;
765 *father_in_tree
= &(current_inst_as_father
->grand_father
);
766 if (left_father_in_tree
!= NULL
) {
767 *left_father_in_tree
= current_inst_as_father
;
769 if (right_father_in_tree
!= NULL
) {
770 *right_father_in_tree
= current_inst_as_father
;
773 printf ("Expression '");
774 mono_print_tree (inst
);
775 printf ("' is a potential father ( ");
776 if (left_father_in_tree
!= NULL
) {
779 if (right_father_in_tree
!= NULL
) {
784 } else if ((area
->current_occurrence
->description
.left_argument
.type
!= MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
) &&
785 (area
->current_occurrence
->description
.right_argument
.type
!= MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
)) {
786 area
->current_occurrence
->occurrence
= inst
;
787 area
->current_occurrence
->previous_tree
= previous_inst
;
788 area
->current_occurrence
->bb_info
= bb_info
;
789 area
->current_occurrence
->is_first_in_bb
= FALSE
;
790 area
->current_occurrence
->is_last_in_bb
= FALSE
;
792 area
->current_occurrence
->father_in_tree
= NULL
;
793 *father_in_tree
= &(area
->current_occurrence
->father_in_tree
);
795 add_occurrence_to_worklist (area
);
797 *father_in_tree
= NULL
;
800 *father_in_tree
= NULL
;
805 * Process a BB, and (recursively) all its children in the dominator tree.
806 * The result is that all the expressions end up in the worklist, and the
807 * auxiliary MonoSsapreBBInfo fields (dt_dfn, dt_descendants) are initialized
808 * (with all the info that comes from the MonoBasicBlock).
811 process_bb (MonoSsapreWorkArea
*area
, MonoBasicBlock
*bb
, int *dt_dfn
, int *upper_descendants
, int current_depth
) {
812 MonoSsapreBBInfo
*bb_info
;
814 GSList
*dominated_bb
;
815 MonoInst
* current_inst
;
816 MonoInst
* previous_inst
;
817 MonoSsapreFatherExpression
** dummy_father_in_tree
;
819 bb_info
= &(area
->bb_infos
[*dt_dfn
]);
820 bb_info
->dt_dfn
= *dt_dfn
;
822 bb_info
->cfg_dfn
= bb
->dfn
;
823 area
->bb_infos_in_cfg_dfn_order
[bb
->dfn
] = bb_info
;
824 bb_info
->in_count
= bb
->in_count
;
825 bb_info
->out_count
= bb
->out_count
;
826 bb_info
->dfrontier
= bb
->dfrontier
;
828 bb_info
->in_bb
= (MonoSsapreBBInfo
**) mono_mempool_alloc (area
->mempool
, sizeof (MonoSsapreBBInfo
*) * (bb
->in_count
));
829 bb_info
->out_bb
= (MonoSsapreBBInfo
**) mono_mempool_alloc (area
->mempool
, sizeof (MonoSsapreBBInfo
*) * (bb
->out_count
));
830 bb_info
->phi_arguments_classes
= (int*) mono_mempool_alloc (area
->mempool
, sizeof (int) * (bb
->in_count
));
832 bb_info
->phi_insertion_point
= NULL
;
834 previous_inst
= NULL
;
835 MONO_BB_FOR_EACH_INS (bb
, current_inst
) {
836 /* Ugly hack to fix missing variable definitions */
837 /* (the SSA construction code should have done it already!) */
838 switch (current_inst
->opcode
) {
847 if ((current_inst
->inst_left
->opcode
== OP_LOCAL
) || (current_inst
->inst_left
->opcode
== OP_ARG
)) {
848 int variable_index
= current_inst
->inst_left
->inst_c0
;
850 if (MONO_VARINFO (area
->cfg
, variable_index
)->def_bb
== NULL
) {
851 if (area
->cfg
->verbose_level
>= 4) {
852 printf ("SSAPRE WARNING: variable %d has no definition, fixing.\n", variable_index
);
854 MONO_VARINFO (area
->cfg
, variable_index
)->def_bb
= bb_info
->bb
;
862 if (is_phi_definition (current_inst
)) {
863 bb_info
->phi_insertion_point
= current_inst
;
866 if (mono_burg_arity
[current_inst
->opcode
] > 0) {
867 process_inst (area
, current_inst
->inst_left
, previous_inst
, &dummy_father_in_tree
, bb_info
);
868 if (mono_burg_arity
[current_inst
->opcode
] > 1) {
869 process_inst (area
, current_inst
->inst_right
, previous_inst
, &dummy_father_in_tree
, bb_info
);
873 previous_inst
= current_inst
;
876 if (current_depth
> area
->dt_depth
) {
877 area
->dt_depth
= current_depth
;
880 for (dominated_bb
= bb
->dominated
; dominated_bb
!= NULL
; dominated_bb
= dominated_bb
->next
) {
881 process_bb (area
, (MonoBasicBlock
*) (dominated_bb
->data
), dt_dfn
, &descendants
, current_depth
+ 1);
883 bb_info
->dt_descendants
= descendants
;
884 *upper_descendants
+= (descendants
+ 1);
888 * Reset the MonoSsapreBBInfo fields that must be recomputed for each expression.
891 clean_bb_infos (MonoSsapreWorkArea
*area
) {
893 for (i
= 0; i
< area
->num_bblocks
; i
++) {
894 MonoSsapreBBInfo
*bb_info
= &(area
->bb_infos
[i
]);
895 bb_info
->dt_covered_by_interesting_BBs
= FALSE
;
896 bb_info
->has_phi
= FALSE
;
897 bb_info
->phi_defines_a_real_occurrence
= FALSE
;
898 bb_info
->phi_is_down_safe
= FALSE
;
899 bb_info
->phi_can_be_available
= FALSE
;
900 bb_info
->phi_is_later
= FALSE
;
901 bb_info
->phi_redundancy_class
= BOTTOM_REDUNDANCY_CLASS
;
902 bb_info
->phi_variable_index
= BOTTOM_REDUNDANCY_CLASS
;
903 bb_info
->has_phi_argument
= FALSE
;
904 bb_info
->phi_argument_has_real_use
= FALSE
;
905 bb_info
->phi_argument_needs_insert
= FALSE
;
906 bb_info
->phi_argument_has_been_processed
= FALSE
;
907 bb_info
->phi_argument_class
= BOTTOM_REDUNDANCY_CLASS
;
908 bb_info
->phi_argument_variable_index
= BOTTOM_REDUNDANCY_CLASS
;
909 bb_info
->phi_argument_defined_by_real_occurrence
= NULL
;
910 bb_info
->phi_argument_defined_by_phi
= NULL
;
911 bb_info
->phi_argument_left_argument_version
= BOTTOM_REDUNDANCY_CLASS
;
912 bb_info
->phi_argument_right_argument_version
= BOTTOM_REDUNDANCY_CLASS
;
913 bb_info
->first_expression_in_bb
= NULL
;
914 bb_info
->next_interesting_bb
= NULL
;
915 bb_info
->next_in_renaming_stack
= NULL
;
916 bb_info
->top_of_local_renaming_stack
= NULL
;
921 * Reset the MonoSsapreWorkArea fields that must be recomputed for each expression.
924 clean_area_infos (MonoSsapreWorkArea
*area
) {
925 mono_bitset_clear_all (area
->left_argument_bb_bitset
);
926 mono_bitset_clear_all (area
->right_argument_bb_bitset
);
927 area
->num_vars
= area
->cfg
->num_varinfo
;
928 area
->top_of_renaming_stack
= NULL
;
929 area
->bb_on_top_of_renaming_stack
= NULL
;
930 area
->first_interesting_bb
= NULL
;
931 area
->saved_occurrences
= 0;
932 area
->reloaded_occurrences
= 0;
933 area
->inserted_occurrences
= 0;
934 area
->unaltered_occurrences
= 0;
935 area
->added_phis
= 0;
936 clean_bb_infos (area
);
940 * Utility function to combine the dominance frontiers of a set of BBs.
943 compute_combined_dfrontier (MonoSsapreWorkArea
*area
, MonoBitSet
* result
, MonoBitSet
*bblocks
)
946 mono_bitset_clear_all (result
);
947 mono_bitset_foreach_bit (bblocks
, i
, area
->num_bblocks
) {
948 mono_bitset_union (result
, area
->bb_infos_in_cfg_dfn_order
[i
]->dfrontier
);
953 * Utility function to compute the combined dominance frontier of a set of BBs.
956 compute_combined_iterated_dfrontier (MonoSsapreWorkArea
*area
, MonoBitSet
*result
, MonoBitSet
*bblocks
, MonoBitSet
*buffer
)
958 gboolean change
= TRUE
;
960 compute_combined_dfrontier (area
, result
, bblocks
);
963 compute_combined_dfrontier (area
, buffer
, result
);
964 mono_bitset_union (buffer
, result
);
966 if (!mono_bitset_equal (buffer
, result
)) {
967 mono_bitset_copyto (buffer
, result
);
974 * See paper, section 5.1, definition of "Dominate"
977 dominates (MonoSsapreBBInfo
*dominator
, MonoSsapreBBInfo
*dominated
) {
978 if ((dominator
->dt_dfn
<= dominated
->dt_dfn
) && (dominated
->dt_dfn
<= (dominator
->dt_dfn
+ dominator
->dt_descendants
))) {
986 * See paper, figure 18, function Set_var_phis
988 static void process_phi_variable_in_phi_insertion (MonoSsapreWorkArea
*area
, gssize variable
, MonoBitSet
*phi_bbs
) {
989 int* phi_definition
= get_phi_definition (area
->cfg
, variable
);
991 if (phi_definition
!= NULL
) {
992 int definition_bb
= MONO_VARINFO (area
->cfg
, variable
)->def_bb
->dfn
;
993 if (! mono_bitset_test (phi_bbs
, definition_bb
)) {
995 mono_bitset_set (phi_bbs
, definition_bb
);
996 for (i
= 0; i
< *phi_definition
; i
++) {
997 process_phi_variable_in_phi_insertion (area
, phi_definition
[i
+1], phi_bbs
);
1004 * See paper, figure 18, function phi_insertion
1007 phi_insertion (MonoSsapreWorkArea
*area
, MonoSsapreExpression
*expression
) {
1008 MonoSsapreExpressionOccurrence
*current_expression
= NULL
;
1009 MonoSsapreExpressionOccurrence
*previous_expression
= NULL
;
1010 MonoSsapreBBInfo
*current_bb
= NULL
;
1011 MonoSsapreBBInfo
*previous_interesting_bb
= NULL
;
1012 int i
, j
, current_bb_dt_dfn
;
1014 MonoSsapreBBInfo
**stack
;
1015 gboolean
*interesting_stack
;
1017 mono_bitset_clear_all (area
->expression_occurrences_buffer
);
1018 for (current_expression
= expression
->occurrences
; current_expression
!= NULL
; current_expression
= current_expression
->next
) {
1019 mono_bitset_set (area
->expression_occurrences_buffer
, current_expression
->bb_info
->cfg_dfn
);
1020 if (current_expression
->description
.left_argument
.type
== MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
) {
1021 process_phi_variable_in_phi_insertion (area
, current_expression
->description
.left_argument
.argument
.ssa_variable
, area
->left_argument_bb_bitset
);
1023 if (current_expression
->description
.right_argument
.type
== MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
) {
1024 process_phi_variable_in_phi_insertion (area
, current_expression
->description
.right_argument
.argument
.ssa_variable
, area
->right_argument_bb_bitset
);
1027 if (previous_expression
!= NULL
) {
1028 if (previous_expression
->bb_info
!= current_expression
->bb_info
) {
1029 previous_expression
->is_last_in_bb
= TRUE
;
1030 current_expression
->is_first_in_bb
= TRUE
;
1031 current_expression
->bb_info
->first_expression_in_bb
= current_expression
;
1034 current_expression
->is_first_in_bb
= TRUE
;
1035 current_expression
->bb_info
->first_expression_in_bb
= current_expression
;
1038 previous_expression
= current_expression
;
1040 previous_expression
->is_last_in_bb
= TRUE
;
1042 compute_combined_iterated_dfrontier (area
, area
->iterated_dfrontier_buffer
, area
->expression_occurrences_buffer
, area
->bb_iteration_buffer
);
1044 mono_bitset_union (area
->iterated_dfrontier_buffer
, area
->left_argument_bb_bitset
);
1045 mono_bitset_union (area
->iterated_dfrontier_buffer
, area
->right_argument_bb_bitset
);
1047 mono_bitset_foreach_bit (area
->iterated_dfrontier_buffer
, i
, area
->num_bblocks
) {
1048 area
->bb_infos_in_cfg_dfn_order
[i
]->has_phi
= TRUE
;
1049 area
->bb_infos_in_cfg_dfn_order
[i
]->phi_can_be_available
= TRUE
;
1050 for (j
= 0; j
< area
->bb_infos_in_cfg_dfn_order
[i
]->in_count
; j
++) {
1051 area
->bb_infos_in_cfg_dfn_order
[i
]->in_bb
[j
]->has_phi_argument
= TRUE
;
1056 stack
= (MonoSsapreBBInfo
**) alloca (sizeof (MonoSsapreBBInfo
*) * (area
->dt_depth
));
1057 interesting_stack
= (gboolean
*) alloca (sizeof (gboolean
) * (area
->dt_depth
));
1059 /* Setup the list of interesting BBs, and their "DT coverage" */
1060 for (current_bb
= area
->bb_infos
, current_bb_dt_dfn
= 0; current_bb_dt_dfn
< area
->num_bblocks
; current_bb
++, current_bb_dt_dfn
++) {
1061 gboolean current_bb_is_interesting
;
1063 if ((current_bb
->first_expression_in_bb
!= NULL
) || (current_bb
->has_phi
) || (current_bb
->has_phi_argument
)) {
1064 current_bb_is_interesting
= TRUE
;
1066 if (previous_interesting_bb
!= NULL
) {
1067 previous_interesting_bb
->next_interesting_bb
= current_bb
;
1069 area
->first_interesting_bb
= current_bb
;
1071 previous_interesting_bb
= current_bb
;
1073 current_bb_is_interesting
= FALSE
;
1077 while ((top
>= 0) && (! dominates (stack
[top
], current_bb
))) {
1078 gboolean top_covers_his_idominator
= ((interesting_stack
[top
]) || (stack
[top
]->dt_covered_by_interesting_BBs
));
1080 if ((top
> 0) && (! top_covers_his_idominator
)) {
1081 stack
[top
- 1]->dt_covered_by_interesting_BBs
= FALSE
;
1092 interesting_stack
[top
] = current_bb_is_interesting
;
1093 stack
[top
] = current_bb
;
1094 if (stack
[top
]->dt_descendants
== 0) {
1095 stack
[top
]->dt_covered_by_interesting_BBs
= FALSE
;
1097 stack
[top
]->dt_covered_by_interesting_BBs
= TRUE
;
1101 gboolean top_covers_his_idominator
= ((interesting_stack
[top
]) || (stack
[top
]->dt_covered_by_interesting_BBs
));
1103 if (! top_covers_his_idominator
) {
1104 stack
[top
- 1]->dt_covered_by_interesting_BBs
= FALSE
;
1112 * Macro that pushes a real occurrence on the stack
1114 #define PUSH_REAL_OCCURRENCE(o) do{\
1115 if (area->bb_on_top_of_renaming_stack != (o)->bb_info) { \
1116 (o)->bb_info->next_in_renaming_stack = area->bb_on_top_of_renaming_stack; \
1117 area->bb_on_top_of_renaming_stack =(o)->bb_info; \
1118 (o)->next_in_renaming_stack = NULL; \
1120 (o)->next_in_renaming_stack = area->top_of_renaming_stack; \
1122 (o)->bb_info->top_of_local_renaming_stack = (o); \
1123 area->top_of_renaming_stack = (o); \
1124 area->bb_on_top_of_renaming_stack->phi_argument_has_real_use = FALSE; \
1128 * Macro that pushes a PHI occurrence on the stack
1130 #define PUSH_PHI_OCCURRENCE(b) do{\
1131 if (area->bb_on_top_of_renaming_stack != (b)) { \
1132 (b)->next_in_renaming_stack = area->bb_on_top_of_renaming_stack; \
1133 area->bb_on_top_of_renaming_stack = (b); \
1135 (b)->top_of_local_renaming_stack = NULL; \
1136 area->top_of_renaming_stack = NULL; \
1137 area->bb_on_top_of_renaming_stack->phi_argument_has_real_use = FALSE; \
1141 * See paper, section 5.4.
1142 * The two passes are coded sequentially (no separate "rename1" and "rename2" functions).
1145 renaming_pass (MonoSsapreWorkArea
*area
) {
1146 MonoSsapreBBInfo
*current_bb
= NULL
;
1147 MonoSsapreBBInfo
*previous_bb
= NULL
;
1148 MonoSsapreExpressionOccurrence
*current_expression
= NULL
;
1149 gssize current_class
= 0;
1151 /* This loop is "rename1" */
1152 for (current_bb
= area
->first_interesting_bb
, previous_bb
= NULL
; current_bb
!= NULL
; previous_bb
= current_bb
, current_bb
= current_bb
->next_interesting_bb
) {
1153 if (previous_bb
!= NULL
) {
1154 if (! dominates (previous_bb
, current_bb
)) {
1155 /* This means we are backtracking in the dominator tree */
1156 MonoSsapreBBInfo
*first_interesting_dominator
= current_bb
->idominator
;
1157 while ((first_interesting_dominator
->next_interesting_bb
== NULL
) && (first_interesting_dominator
->idominator
!= NULL
)) {
1158 first_interesting_dominator
= first_interesting_dominator
->idominator
;
1160 current_bb
->phi_argument_has_real_use
= first_interesting_dominator
->phi_argument_has_real_use
;
1162 if ((area
->bb_on_top_of_renaming_stack
!= NULL
) && (area
->top_of_renaming_stack
== NULL
) && (previous_bb
->phi_argument_has_real_use
== FALSE
)) {
1164 printf ("Clearing down safe in PHI %d because of backtracking (current block is [bb %d [ID %d]], previous block is [bb %d [ID %d]])\n",
1165 area
->bb_on_top_of_renaming_stack
->phi_redundancy_class
, current_bb
->cfg_dfn
, current_bb
->bb
->block_num
, previous_bb
->cfg_dfn
, previous_bb
->bb
->block_num
);
1167 area
->bb_on_top_of_renaming_stack
->phi_is_down_safe
= FALSE
;
1169 while ((area
->bb_on_top_of_renaming_stack
!= NULL
) && ! dominates (area
->bb_on_top_of_renaming_stack
, current_bb
)) {
1170 MonoSsapreBBInfo
*top_bb
= area
->bb_on_top_of_renaming_stack
;
1171 if (top_bb
->next_in_renaming_stack
!= NULL
) {
1172 area
->top_of_renaming_stack
= top_bb
->next_in_renaming_stack
->top_of_local_renaming_stack
;
1174 area
->top_of_renaming_stack
= NULL
;
1176 area
->bb_on_top_of_renaming_stack
= top_bb
->next_in_renaming_stack
;
1179 printf ("Backtracked, getting real use flag from bb %d [ID %d], current top of the stack is class ",
1180 first_interesting_dominator
->cfg_dfn
, first_interesting_dominator
->bb
->block_num
);
1181 if (area
->top_of_renaming_stack
!= NULL
) {
1182 printf ("%d\n", area
->top_of_renaming_stack
->redundancy_class
);
1183 } else if (area
->bb_on_top_of_renaming_stack
!= NULL
) {
1184 printf ("%d\n", area
->bb_on_top_of_renaming_stack
->phi_redundancy_class
);
1186 printf ("BOTTOM\n");
1190 /* With no backtracking we just propagate the flag */
1191 current_bb
->phi_argument_has_real_use
= previous_bb
->phi_argument_has_real_use
;
1194 /* Start condition */
1195 current_bb
->phi_argument_has_real_use
= FALSE
;
1198 printf ("Real use flag is %s at the beginning of block [bb %d [ID %d]]\n",
1199 GBOOLEAN_TO_STRING (current_bb
->phi_argument_has_real_use
), current_bb
->cfg_dfn
, current_bb
->bb
->block_num
);
1202 if (current_bb
->has_phi
) {
1203 if (current_bb
->dt_covered_by_interesting_BBs
) {
1204 current_bb
->phi_is_down_safe
= TRUE
;
1206 current_bb
->phi_is_down_safe
= FALSE
;
1208 current_bb
->phi_redundancy_class
= current_class
;
1210 PUSH_PHI_OCCURRENCE (current_bb
);
1212 printf ("Assigning class %d to PHI in bb %d [ID %d]\n",
1213 current_bb
->phi_redundancy_class
, current_bb
->cfg_dfn
, current_bb
->bb
->block_num
);
1217 for (current_expression
= current_bb
->first_expression_in_bb
; (current_expression
!= NULL
) && (current_expression
->bb_info
== current_bb
); current_expression
= current_expression
->next
) {
1218 if (area
->top_of_renaming_stack
!= NULL
) {
1219 MonoSsapreExpressionOccurrence
*top
= area
->top_of_renaming_stack
;
1221 if (((current_expression
->description
.left_argument
.type
!= MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
) ||
1222 (current_expression
->description
.left_argument
.argument
.ssa_variable
== top
->description
.left_argument
.argument
.ssa_variable
)) &&
1223 ((current_expression
->description
.right_argument
.type
!= MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
) ||
1224 (current_expression
->description
.right_argument
.argument
.ssa_variable
== top
->description
.right_argument
.argument
.ssa_variable
))) {
1225 current_expression
->redundancy_class
= top
->redundancy_class
;
1226 current_expression
->defined_by_real_occurrence
= top
;
1228 printf ("Using class %d for occurrence '", current_expression
->redundancy_class
);
1229 print_expression_description (&(current_expression
->description
));
1230 printf ("' in bb %d [ID %d]\n", current_bb
->cfg_dfn
, current_bb
->bb
->block_num
);
1233 current_expression
->redundancy_class
= current_class
;
1235 current_expression
->defined_by_real_occurrence
= NULL
;
1236 PUSH_REAL_OCCURRENCE (current_expression
);
1238 printf ("Assigning class %d to occurrence '", current_expression
->redundancy_class
);
1239 print_expression_description (&(current_expression
->description
));
1240 printf ("' in bb %d [ID %d]\n", current_bb
->cfg_dfn
, current_bb
->bb
->block_num
);
1243 current_expression
->defined_by_phi
= NULL
;
1244 } else if (area
->bb_on_top_of_renaming_stack
!= NULL
) {
1245 MonoSsapreBBInfo
*phi_bb
= area
->bb_on_top_of_renaming_stack
;
1246 gssize left_argument_version
= ((current_expression
->description
.left_argument
.type
== MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
)?
1247 (current_expression
->description
.left_argument
.argument
.ssa_variable
):BOTTOM_REDUNDANCY_CLASS
);
1248 gssize right_argument_version
= ((current_expression
->description
.right_argument
.type
== MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
)?
1249 (current_expression
->description
.right_argument
.argument
.ssa_variable
):BOTTOM_REDUNDANCY_CLASS
);
1251 /* See remark in section 5.4 about the dominance relation between PHI */
1252 /* occurrences and phi definitions */
1253 MonoSsapreBBInfo
*left_argument_definition_bb
= ((left_argument_version
!= BOTTOM_REDUNDANCY_CLASS
)?
1254 (get_bb_info_of_definition (area
, left_argument_version
)):NULL
);
1255 MonoSsapreBBInfo
*right_argument_definition_bb
= ((right_argument_version
!= BOTTOM_REDUNDANCY_CLASS
)?
1256 (get_bb_info_of_definition (area
, right_argument_version
)):NULL
);
1258 gboolean left_same_class_condition
= ((left_argument_definition_bb
== NULL
) || ((left_argument_definition_bb
!= phi_bb
) ? dominates (left_argument_definition_bb
, phi_bb
) :
1259 (IS_PHI_DEFINITION (left_argument_version
) ? TRUE
: FALSE
)));
1260 gboolean right_same_class_condition
= ((right_argument_definition_bb
== NULL
) || ((right_argument_definition_bb
!= phi_bb
) ? dominates (right_argument_definition_bb
, phi_bb
) :
1261 (IS_PHI_DEFINITION (right_argument_version
) ? TRUE
: FALSE
)));
1263 if (left_same_class_condition
&& right_same_class_condition
) {
1266 phi_bb
->phi_defines_a_real_occurrence
= TRUE
;
1267 current_bb
->phi_argument_has_real_use
= TRUE
;
1268 current_expression
->redundancy_class
= phi_bb
->phi_redundancy_class
;
1269 current_expression
->defined_by_phi
= phi_bb
;
1271 /* If this PHI was not "covered", it is not down safe. */
1272 /* However, if the real occurrence is in the same BB, it */
1273 /* actually is down safe */
1274 if (phi_bb
== current_bb
) {
1276 printf ("PHI in bb %d [ID %d] defined occurrence %d in the same BB, so it is down safe\n", phi_bb
->cfg_dfn
, phi_bb
->bb
->block_num
, current_expression
->redundancy_class
);
1278 phi_bb
->phi_is_down_safe
= TRUE
;
1282 * Major difference from the paper here...
1283 * Instead of maintaining "set_for_rename2" (see figure 20), we just
1284 * compute "phi_argument_left_argument_version" (and right) here, and
1285 * use that in rename2, saving us the hassle of maintaining a set
1286 * data structure (and the related allocations).
1288 for (phi_argument
= 0; phi_argument
< phi_bb
->in_count
; phi_argument
++) {
1289 MonoSsapreBBInfo
*previous_bb
= phi_bb
->in_bb
[phi_argument
];
1290 if (left_argument_version
!= BOTTOM_REDUNDANCY_CLASS
) {
1291 previous_bb
->phi_argument_left_argument_version
= get_variable_version_at_predecessor_bb (area
,
1292 left_argument_version
, phi_bb
, phi_argument
);
1294 if (right_argument_version
!= BOTTOM_REDUNDANCY_CLASS
) {
1295 previous_bb
->phi_argument_right_argument_version
= get_variable_version_at_predecessor_bb (area
,
1296 right_argument_version
, phi_bb
, phi_argument
);
1300 printf ("Using class %d for occurrence '", current_expression
->redundancy_class
);
1301 print_expression_description (&(current_expression
->description
));
1302 printf ("' in bb %d [ID %d] (Real use flag is now TRUE)\n", current_bb
->cfg_dfn
, current_bb
->bb
->block_num
);
1305 current_expression
->redundancy_class
= current_class
;
1307 current_expression
->defined_by_phi
= NULL
;
1308 PUSH_REAL_OCCURRENCE (current_expression
);
1309 phi_bb
->phi_is_down_safe
= FALSE
;
1311 printf ("Assigning class %d to occurrence '", current_expression
->redundancy_class
);
1312 print_expression_description (&(current_expression
->description
));
1313 printf ("' in bb %d [ID %d]\n", current_bb
->cfg_dfn
, current_bb
->bb
->block_num
);
1314 printf ("Clearing down safe in PHI %d because of real occurrence %d\n",
1315 phi_bb
->phi_redundancy_class
, current_expression
->redundancy_class
);
1318 current_expression
->defined_by_real_occurrence
= NULL
;
1320 current_expression
->redundancy_class
= current_class
;
1322 current_expression
->defined_by_real_occurrence
= NULL
;
1323 current_expression
->defined_by_phi
= NULL
;
1324 PUSH_REAL_OCCURRENCE (current_expression
);
1326 printf ("Assigning class %d to occurrence '", current_expression
->redundancy_class
);
1327 print_expression_description (&(current_expression
->description
));
1328 printf ("' in bb %d [ID %d]\n", current_bb
->cfg_dfn
, current_bb
->bb
->block_num
);
1333 if (current_bb
->has_phi_argument
) {
1334 if (area
->top_of_renaming_stack
!= NULL
) {
1335 current_bb
->phi_argument_defined_by_real_occurrence
= area
->top_of_renaming_stack
;
1336 current_bb
->phi_argument_class
= area
->top_of_renaming_stack
->redundancy_class
;
1337 } else if (area
->bb_on_top_of_renaming_stack
!= NULL
) {
1338 current_bb
->phi_argument_defined_by_phi
= area
->bb_on_top_of_renaming_stack
;
1339 current_bb
->phi_argument_class
= area
->bb_on_top_of_renaming_stack
->phi_redundancy_class
;
1341 current_bb
->phi_argument_class
= BOTTOM_REDUNDANCY_CLASS
;
1343 if ((DUMP_SSAPRE
) && (current_bb
->phi_argument_class
!= BOTTOM_REDUNDANCY_CLASS
)) {
1344 printf ("Temporarily using class %d for PHI argument in bb %d [ID %d]\n",
1345 current_bb
->phi_argument_class
, current_bb
->cfg_dfn
, current_bb
->bb
->block_num
);
1349 if ((area
->bb_on_top_of_renaming_stack
!= NULL
) && (area
->top_of_renaming_stack
== NULL
) && (previous_bb
->phi_argument_has_real_use
== FALSE
)) {
1351 printf ("Clearing down safe in PHI %d because of backtracking (previous block is [bb %d [ID %d]])\n",
1352 area
->bb_on_top_of_renaming_stack
->phi_redundancy_class
, previous_bb
->cfg_dfn
, previous_bb
->bb
->block_num
);
1354 area
->bb_on_top_of_renaming_stack
->phi_is_down_safe
= FALSE
;
1356 area
->number_of_classes
= current_class
;
1358 /* This loop is "rename2" */
1359 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
1360 if (current_bb
->has_phi_argument
) {
1361 if ((current_bb
->phi_argument_left_argument_version
!= BOTTOM_REDUNDANCY_CLASS
) || (current_bb
->phi_argument_right_argument_version
!= BOTTOM_REDUNDANCY_CLASS
)) {
1362 if (current_bb
->phi_argument_defined_by_real_occurrence
!= NULL
) {
1363 if (((current_bb
->phi_argument_left_argument_version
!= BOTTOM_REDUNDANCY_CLASS
) &&
1364 (current_bb
->phi_argument_left_argument_version
!= current_bb
->phi_argument_defined_by_real_occurrence
->description
.left_argument
.argument
.ssa_variable
)) ||
1365 ((current_bb
->phi_argument_right_argument_version
!= BOTTOM_REDUNDANCY_CLASS
) &&
1366 (current_bb
->phi_argument_right_argument_version
!= current_bb
->phi_argument_defined_by_real_occurrence
->description
.right_argument
.argument
.ssa_variable
))) {
1367 current_bb
->phi_argument_class
= BOTTOM_REDUNDANCY_CLASS
;
1369 } else if (current_bb
->phi_argument_defined_by_phi
!= NULL
) {
1370 MonoSsapreBBInfo
*phi_bb
= current_bb
->phi_argument_defined_by_phi
;
1371 MonoSsapreBBInfo
*left_argument_definition_bb
= (current_bb
->phi_argument_left_argument_version
!= BOTTOM_REDUNDANCY_CLASS
) ?
1372 get_bb_info_of_definition (area
, current_bb
->phi_argument_left_argument_version
) : NULL
;
1373 MonoSsapreBBInfo
*right_argument_definition_bb
= (current_bb
->phi_argument_right_argument_version
!= BOTTOM_REDUNDANCY_CLASS
) ?
1374 get_bb_info_of_definition (area
, current_bb
->phi_argument_right_argument_version
) : NULL
;
1375 /* See remark in section 5.4 about the dominance relation between PHI */
1376 /* occurrences and phi definitions */
1377 gboolean left_bottom_condition
= ((left_argument_definition_bb
!= NULL
) && ! ((left_argument_definition_bb
!= phi_bb
) ? dominates (left_argument_definition_bb
, phi_bb
) :
1378 (IS_PHI_DEFINITION (current_bb
->phi_argument_left_argument_version
) ? TRUE
: FALSE
)));
1379 gboolean right_bottom_condition
= ((right_argument_definition_bb
!= NULL
) && ! ((right_argument_definition_bb
!= phi_bb
) ? dominates (right_argument_definition_bb
, phi_bb
) :
1380 (IS_PHI_DEFINITION (current_bb
->phi_argument_right_argument_version
) ? TRUE
: FALSE
)));
1382 if (left_bottom_condition
|| right_bottom_condition
) {
1383 current_bb
->phi_argument_class
= BOTTOM_REDUNDANCY_CLASS
;
1386 current_bb
->phi_argument_class
= BOTTOM_REDUNDANCY_CLASS
;
1389 current_bb
->phi_argument_class
= BOTTOM_REDUNDANCY_CLASS
;
1392 if (current_bb
->phi_argument_class
== BOTTOM_REDUNDANCY_CLASS
) {
1393 if ((current_bb
->phi_argument_defined_by_phi
!= NULL
) && (! current_bb
->phi_argument_has_real_use
)) {
1395 printf ("Clearing down safe in PHI %d because PHI argument in block [bb %d [ID %d]] is BOTTOM\n",
1396 current_bb
->phi_argument_defined_by_phi
->phi_redundancy_class
, current_bb
->cfg_dfn
, current_bb
->bb
->block_num
);
1398 current_bb
->phi_argument_defined_by_phi
->phi_is_down_safe
= FALSE
;
1400 current_bb
->phi_argument_has_real_use
= FALSE
;
1403 printf ("Cleared real use flag in block [bb %d [ID %d]] because phi argument class is now BOTTOM\n",
1404 current_bb
->cfg_dfn
, current_bb
->bb
->block_num
);
1410 /* Final quick pass to copy the result of "rename2" into PHI nodes */
1411 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
1412 if (current_bb
->has_phi
) {
1414 for (i
= 0; i
< current_bb
->in_count
; i
++) {
1415 current_bb
->phi_arguments_classes
[i
] = current_bb
->in_bb
[i
]->phi_argument_class
;
1421 #undef PUSH_REAL_OCCURRENCE
1422 #undef PUSH_PHI_OCCURRENCE
1425 * See paper, figure 8
1428 reset_down_safe (MonoSsapreBBInfo
*phi_argument
) {
1429 if ((phi_argument
->phi_argument_class
!= BOTTOM_REDUNDANCY_CLASS
) && (! phi_argument
->phi_argument_has_real_use
) && (phi_argument
->phi_argument_defined_by_phi
!= NULL
) && (phi_argument
->phi_argument_defined_by_phi
->phi_is_down_safe
)) {
1431 MonoSsapreBBInfo
*phi
= phi_argument
->phi_argument_defined_by_phi
;
1432 phi
->phi_is_down_safe
= FALSE
;
1433 for (i
= 0; i
< phi
->in_count
; i
++) {
1434 reset_down_safe (phi
->in_bb
[i
]);
1440 * See paper, figure 8
1443 down_safety (MonoSsapreWorkArea
*area
) {
1444 MonoSsapreBBInfo
*current_bb
= NULL
;
1446 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
1447 if (current_bb
->has_phi
) {
1448 if (! current_bb
->phi_is_down_safe
) {
1450 for (i
= 0; i
< current_bb
->in_count
; i
++) {
1451 reset_down_safe (current_bb
->in_bb
[i
]);
1459 * See paper, figure 10
1462 reset_can_be_available (MonoSsapreWorkArea
*area
, MonoSsapreBBInfo
*phi
) {
1463 MonoSsapreBBInfo
*current_bb
= NULL
;
1466 printf ("Resetting availability for PHI %d in block [bb %d [ID %d]]\n",
1467 phi
->phi_redundancy_class
, phi
->cfg_dfn
, phi
->bb
->block_num
);
1470 phi
->phi_can_be_available
= FALSE
;
1471 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
1472 if (current_bb
->has_phi
) {
1473 gboolean phi_is_interesting
= FALSE
;
1476 for (i
= 0; i
< current_bb
->in_count
; i
++) {
1477 MonoSsapreBBInfo
*phi_argument
= current_bb
->in_bb
[i
];
1478 if ((phi_argument
->phi_argument_class
== current_bb
->phi_redundancy_class
) && (! phi_argument
->phi_argument_has_real_use
)) {
1479 phi_is_interesting
= TRUE
;
1484 if (phi_is_interesting
&& (! current_bb
->phi_is_down_safe
) && (current_bb
->phi_can_be_available
)) {
1485 reset_can_be_available (area
, current_bb
);
1492 * See paper, figure 10
1495 compute_can_be_available (MonoSsapreWorkArea
*area
) {
1496 MonoSsapreBBInfo
*current_bb
= NULL
;
1498 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
1499 if (current_bb
->has_phi
) {
1500 if ((! current_bb
->phi_is_down_safe
) && (current_bb
->phi_can_be_available
)) {
1501 gboolean phi_is_interesting
= FALSE
;
1504 for (i
= 0; i
< current_bb
->in_count
; i
++) {
1505 if (current_bb
->phi_arguments_classes
[i
] == BOTTOM_REDUNDANCY_CLASS
) {
1506 phi_is_interesting
= TRUE
;
1511 if (phi_is_interesting
) {
1513 printf ("Availability computation working on PHI %d in block [bb %d [ID %d]]\n",
1514 current_bb
->phi_redundancy_class
, current_bb
->cfg_dfn
, current_bb
->bb
->block_num
);
1516 reset_can_be_available (area
, current_bb
);
1524 * See paper, figure 10
1527 reset_later (MonoSsapreWorkArea
*area
, MonoSsapreBBInfo
*phi
) {
1528 MonoSsapreBBInfo
*current_bb
= NULL
;
1530 if (phi
->phi_is_later
) {
1531 phi
->phi_is_later
= FALSE
;
1532 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
1533 if (current_bb
->has_phi
) {
1534 gboolean phi_is_interesting
= FALSE
;
1537 for (i
= 0; i
< current_bb
->in_count
; i
++) {
1538 MonoSsapreBBInfo
*phi_argument
= current_bb
->in_bb
[i
];
1539 if (phi_argument
->phi_argument_class
== current_bb
->phi_redundancy_class
) {
1540 phi_is_interesting
= TRUE
;
1545 if (phi_is_interesting
) {
1546 reset_later (area
, current_bb
);
1554 * See paper, figure 10
1557 compute_later (MonoSsapreWorkArea
*area
) {
1558 MonoSsapreBBInfo
*current_bb
= NULL
;
1560 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
1561 if (current_bb
->has_phi
) {
1562 current_bb
->phi_is_later
= current_bb
->phi_can_be_available
;
1565 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
1566 if (current_bb
->has_phi
) {
1567 if (current_bb
->phi_is_later
) {
1568 gboolean phi_is_interesting
= FALSE
;
1571 for (i
= 0; i
< current_bb
->in_count
; i
++) {
1572 MonoSsapreBBInfo
*phi_argument
= current_bb
->in_bb
[i
];
1573 if ((phi_argument
->phi_argument_class
!= BOTTOM_REDUNDANCY_CLASS
) && (phi_argument
->phi_argument_has_real_use
)) {
1574 phi_is_interesting
= TRUE
;
1579 if (phi_is_interesting
) {
1580 reset_later (area
, current_bb
);
1588 * See paper, figure 12, function Finalize_1
1590 static void finalize_availability_and_reload (MonoSsapreWorkArea
*area
, MonoSsapreAvailabilityTableElement
*availability_table
) {
1591 MonoSsapreBBInfo
*current_bb
= NULL
;
1592 MonoSsapreExpressionOccurrence
*current_expression
= NULL
;
1594 area
->occurrences_scheduled_for_reloading
= 0;
1595 area
->arguments_scheduled_for_insertion
= 0;
1596 area
->dominating_arguments_scheduled_for_insertion
= 0;
1598 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
1599 if (current_bb
->has_phi
) {
1600 if (current_bb
->phi_can_be_available
&& ! current_bb
->phi_is_later
) {
1601 availability_table
[current_bb
->phi_redundancy_class
].class_defined_by_phi
= current_bb
;
1605 for (current_expression
= current_bb
->first_expression_in_bb
; (current_expression
!= NULL
) && (current_expression
->bb_info
== current_bb
); current_expression
= current_expression
->next
) {
1606 MonoSsapreBBInfo
*defining_bb
= availability_table
[current_expression
->redundancy_class
].class_defined_by_phi
;
1607 if (defining_bb
== NULL
&& availability_table
[current_expression
->redundancy_class
].class_defined_by_real_occurrence
!= NULL
) {
1608 defining_bb
= availability_table
[current_expression
->redundancy_class
].class_defined_by_real_occurrence
->bb_info
;
1610 if (defining_bb
!= NULL
) {
1611 if (! dominates (defining_bb
, current_bb
)) {
1616 if (defining_bb
== NULL
) {
1617 current_expression
->reload
= FALSE
;
1618 availability_table
[current_expression
->redundancy_class
].class_defined_by_real_occurrence
= current_expression
;
1620 current_expression
->reload
= TRUE
;
1622 area
->occurrences_scheduled_for_reloading
++;
1624 current_expression
->defined_by_phi
= availability_table
[current_expression
->redundancy_class
].class_defined_by_phi
;
1625 current_expression
->defined_by_real_occurrence
= availability_table
[current_expression
->redundancy_class
].class_defined_by_real_occurrence
;
1628 current_expression
->save
= FALSE
;
1631 if (current_bb
->has_phi_argument
) {
1632 MonoSsapreBBInfo
*phi_bb
= current_bb
->out_bb
[0];
1633 if (((phi_bb
->phi_can_be_available
) && (! phi_bb
->phi_is_later
)) &&
1634 ((current_bb
->phi_argument_class
== BOTTOM_REDUNDANCY_CLASS
) ||
1635 ((current_bb
->phi_argument_has_real_use
== FALSE
) && (current_bb
->phi_argument_defined_by_phi
!= NULL
) &&
1636 (! ((current_bb
->phi_argument_defined_by_phi
->phi_can_be_available
) && (! current_bb
->phi_argument_defined_by_phi
->phi_is_later
)))
1638 current_bb
->phi_argument_needs_insert
= TRUE
;
1640 area
->arguments_scheduled_for_insertion
++;
1641 if (dominates (current_bb
, phi_bb
)) {
1642 area
->dominating_arguments_scheduled_for_insertion
++;
1645 current_bb
->phi_argument_defined_by_real_occurrence
= NULL
;
1646 current_bb
->phi_argument_defined_by_phi
= NULL
;
1648 current_bb
->phi_argument_needs_insert
= FALSE
;
1649 if (current_bb
->phi_argument_class
!= BOTTOM_REDUNDANCY_CLASS
) {
1650 current_bb
->phi_argument_defined_by_real_occurrence
= availability_table
[current_bb
->phi_argument_class
].class_defined_by_real_occurrence
;
1651 current_bb
->phi_argument_defined_by_phi
= availability_table
[current_bb
->phi_argument_class
].class_defined_by_phi
;
1655 current_bb
->phi_argument_has_been_processed
= FALSE
;
1661 * See paper, figure 13, function Set_save
1663 static void set_save (MonoSsapreBBInfo
*phi_occurrance
, MonoSsapreExpressionOccurrence
*real_occurrance
) {
1664 if (real_occurrance
!= NULL
) {
1665 real_occurrance
->save
= TRUE
;
1666 } else if (phi_occurrance
!= NULL
) {
1668 for (i
= 0; i
< phi_occurrance
->in_count
; i
++) {
1669 MonoSsapreBBInfo
*phi_argument
= phi_occurrance
->in_bb
[i
];
1670 if (! phi_argument
->phi_argument_has_been_processed
) {
1671 phi_argument
->phi_argument_has_been_processed
= TRUE
;
1672 set_save (phi_argument
->phi_argument_defined_by_phi
, phi_argument
->phi_argument_defined_by_real_occurrence
);
1679 * See paper, figure 13, function Finalize_2 (note that we still don't do
1680 * extraneous PHI elimination, see function Set_replacement)
1682 static void finalize_save (MonoSsapreWorkArea
*area
) {
1683 MonoSsapreBBInfo
*current_bb
= NULL
;
1684 MonoSsapreExpressionOccurrence
*current_expression
= NULL
;
1686 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
1687 for (current_expression
= current_bb
->first_expression_in_bb
; (current_expression
!= NULL
) && (current_expression
->bb_info
== current_bb
); current_expression
= current_expression
->next
) {
1688 if (current_expression
->reload
) {
1689 set_save (current_expression
->defined_by_phi
, current_expression
->defined_by_real_occurrence
);
1693 if ((current_bb
->has_phi_argument
) &&
1694 (! current_bb
->phi_argument_needs_insert
) &&
1695 (current_bb
->phi_argument_class
!= BOTTOM_REDUNDANCY_CLASS
) &&
1696 (current_bb
->phi_argument_defined_by_real_occurrence
!= NULL
)) {
1697 current_bb
->phi_argument_defined_by_real_occurrence
->save
= TRUE
;
1702 #define OP_IS_CHEAP(op) (((op)==CEE_ADD)||((op)==CEE_SUB))
1703 #define EXPRESSION_HAS_ICONST(d) (((d).left_argument.type==MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT)||((d).right_argument.type==MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT))
1704 #define EXPRESSION_IS_CHEAP(d) ((OP_IS_CHEAP ((d).opcode))&&(EXPRESSION_HAS_ICONST ((d))))
1705 #define REDUNDANCY_IS_SMALL(a) (((a)->occurrences_scheduled_for_reloading < 2)&&((a)->dominating_arguments_scheduled_for_insertion < 1))
1708 * Perform all "finalize" steps.
1709 * Return TRUE if we must go on with code_motion.
1711 static gboolean
finalize (MonoSsapreWorkArea
*area
) {
1712 MonoSsapreAvailabilityTableElement
*availability_table
= alloca (sizeof (MonoSsapreAvailabilityTableElement
) * (area
->number_of_classes
));
1715 for (i
= 0; i
< area
->number_of_classes
; i
++) {
1716 availability_table
[i
].class_defined_by_phi
= NULL
;
1717 availability_table
[i
].class_defined_by_real_occurrence
= NULL
;
1720 finalize_availability_and_reload (area
, availability_table
);
1722 /* Tuning: if the redundancy is not worth handling, give up */
1723 if ((EXPRESSION_IS_CHEAP (area
->current_expression
->description
)) && (REDUNDANCY_IS_SMALL (area
))) {
1726 finalize_save (area
);
1732 * Macros that help in creating constants
1734 #define NEW_INST(dest,op) do { \
1735 (dest) = mono_mempool_alloc0 (area->cfg->mempool, sizeof (MonoInst)); \
1736 (dest)->opcode = (op); \
1739 #define NEW_I4(dest,val) do { \
1740 NEW_INST ((dest), OP_ICONST); \
1741 (dest)->inst_c0 = (val); \
1742 (dest)->type = STACK_I4; \
1745 #define NEW_I8(dest,val) do { \
1746 NEW_INST ((dest), OP_I8CONST); \
1747 (dest)->inst_l = (val); \
1748 (dest)->type = STACK_I8; \
1751 #define NEW_R4(dest,f) do { \
1752 NEW_INST ((dest), OP_R4CONST); \
1753 (dest)->inst_p0 = f; \
1754 (dest)->type = STACK_R8; \
1757 #define NEW_R8(dest,d) do { \
1758 NEW_INST ((dest), OP_R8CONST); \
1759 (dest)->inst_p0 = d; \
1760 (dest)->type = STACK_R8; \
1764 * Create a MonoInst that represents an expression argument
1767 create_expression_argument (MonoSsapreWorkArea
*area
, MonoSsapreExpressionArgument
*argument
) {
1770 switch (argument
->type
) {
1771 case MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT
:
1773 case MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
:
1774 return mono_compile_create_var_load (area
->cfg
, argument
->argument
.ssa_variable
);
1775 case MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT
:
1776 NEW_I4 (result
, argument
->argument
.integer_constant
);
1778 case MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT
:
1779 NEW_I8 (result
, *(argument
->argument
.long_constant
));
1781 case MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT
:
1782 NEW_R4 (result
, argument
->argument
.float_constant
);
1784 case MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT
:
1785 NEW_R8 (result
, argument
->argument
.double_constant
);
1787 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE
:
1788 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
:
1790 g_assert_not_reached ();
1796 * Create a MonoInst that represents an expression
1799 create_expression (MonoSsapreWorkArea
*area
, MonoSsapreExpressionDescription
*expression
, MonoInst
*prototype_occurrence
) {
1801 NEW_INST (result
, expression
->opcode
);
1802 *result
= *prototype_occurrence
;
1803 result
->inst_left
= create_expression_argument (area
, &(expression
->left_argument
));
1804 result
->inst_right
= create_expression_argument (area
, &(expression
->right_argument
));
1809 * Handles the father expression of a MonoInst that has been turned
1810 * into a load (eventually inserting it into the worklist).
1811 * Assumes "current_expression->father_in_tree != NULL".
1814 handle_father_expression (MonoSsapreWorkArea
*area
, MonoSsapreExpressionOccurrence
*current_expression
, MonoInst
*previous_tree
) {
1816 printf ("After reload, father expression becomes ");
1817 mono_print_tree_nl (current_expression
->father_in_tree
->father_occurrence
);
1820 analyze_expression (current_expression
->father_in_tree
->father_occurrence
, &(area
->current_occurrence
->description
));
1821 if ((area
->current_occurrence
->description
.opcode
!= 0) &&
1822 (area
->current_occurrence
->description
.left_argument
.type
!= MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
) &&
1823 (area
->current_occurrence
->description
.right_argument
.type
!= MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY
)) {
1824 area
->current_occurrence
->occurrence
= current_expression
->father_in_tree
->father_occurrence
;
1825 area
->current_occurrence
->previous_tree
= previous_tree
;
1826 area
->current_occurrence
->father_in_tree
= current_expression
->father_in_tree
->grand_father
;
1827 area
->current_occurrence
->bb_info
= current_expression
->bb_info
;
1828 area
->current_occurrence
->is_first_in_bb
= FALSE
;
1829 area
->current_occurrence
->is_last_in_bb
= FALSE
;
1830 add_occurrence_to_worklist (area
);
1835 * See paper, section 3.6
1837 static void code_motion (MonoSsapreWorkArea
*area
) {
1838 MonoSsapreBBInfo
*current_bb
= NULL
;
1839 MonoSsapreExpressionOccurrence
*current_expression
= NULL
;
1840 gssize original_variable_index
= BOTTOM_REDUNDANCY_CLASS
;
1841 MonoInst prototype_occurrence
;
1842 prototype_occurrence
.opcode
= 0;
1844 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
1845 if ((current_bb
->has_phi
) && (current_bb
->phi_can_be_available
&& ! current_bb
->phi_is_later
)) {
1846 MonoInst
*new_var
= mono_compile_create_var (area
->cfg
, area
->current_expression
->type
, OP_LOCAL
);
1847 current_bb
->phi_variable_index
= new_var
->inst_c0
;
1848 if (original_variable_index
== BOTTOM_REDUNDANCY_CLASS
) {
1849 original_variable_index
= new_var
->inst_c0
;
1851 MONO_VARINFO (area
->cfg
, new_var
->inst_c0
)->reg
= original_variable_index
;
1852 MONO_VARINFO (area
->cfg
, new_var
->inst_c0
)->def_bb
= current_bb
->bb
;
1854 current_bb
->phi_variable_index
= BOTTOM_REDUNDANCY_CLASS
;
1857 for (current_expression
= current_bb
->first_expression_in_bb
; (current_expression
!= NULL
) && (current_expression
->bb_info
== current_bb
); current_expression
= current_expression
->next
) {
1858 if (prototype_occurrence
.opcode
== 0) {
1859 prototype_occurrence
= *(current_expression
->occurrence
);
1861 if (current_expression
->save
) {
1862 MonoInst
*new_var
= mono_compile_create_var (area
->cfg
, area
->current_expression
->type
, OP_LOCAL
);
1863 current_expression
->variable_index
= new_var
->inst_c0
;
1864 if (original_variable_index
== BOTTOM_REDUNDANCY_CLASS
) {
1865 original_variable_index
= new_var
->inst_c0
;
1867 MONO_VARINFO (area
->cfg
, new_var
->inst_c0
)->reg
= original_variable_index
;
1868 MONO_VARINFO (area
->cfg
, new_var
->inst_c0
)->def_bb
= current_bb
->bb
;
1870 current_expression
->variable_index
= BOTTOM_REDUNDANCY_CLASS
;
1874 if ((current_bb
->has_phi_argument
) && (current_bb
->phi_argument_needs_insert
)) {
1875 MonoInst
*new_var
= mono_compile_create_var (area
->cfg
, area
->current_expression
->type
, OP_LOCAL
);
1876 current_bb
->phi_argument_variable_index
= new_var
->inst_c0
;
1877 if (original_variable_index
== BOTTOM_REDUNDANCY_CLASS
) {
1878 original_variable_index
= new_var
->inst_c0
;
1880 MONO_VARINFO (area
->cfg
, new_var
->inst_c0
)->reg
= original_variable_index
;
1881 MONO_VARINFO (area
->cfg
, new_var
->inst_c0
)->def_bb
= current_bb
->bb
;
1883 current_bb
->phi_argument_variable_index
= BOTTOM_REDUNDANCY_CLASS
;
1887 for (current_bb
= area
->first_interesting_bb
; current_bb
!= NULL
; current_bb
= current_bb
->next_interesting_bb
) {
1888 if (current_bb
->phi_variable_index
!= BOTTOM_REDUNDANCY_CLASS
) {
1893 NEW_INST (phi
, OP_PHI
);
1894 phi
->inst_c0
= MONO_VARINFO (area
->cfg
, current_bb
->phi_variable_index
)->reg
;
1895 phi
->inst_phi_args
= mono_mempool_alloc (area
->cfg
->mempool
, (sizeof (int) * ((current_bb
->in_count
) + 1)));
1896 phi
->inst_phi_args
[0] = current_bb
->in_count
;
1897 for (in_bb
= 0; in_bb
< current_bb
->in_count
; in_bb
++) {
1898 gssize phi_argument_variable_index
= current_bb
->in_bb
[in_bb
]->phi_argument_variable_index
;
1899 if (phi_argument_variable_index
== BOTTOM_REDUNDANCY_CLASS
) {
1900 MonoSsapreBBInfo
*phi_argument_bb
= current_bb
->in_bb
[in_bb
];
1901 if (phi_argument_bb
->phi_argument_defined_by_phi
!=NULL
) {
1902 phi_argument_variable_index
= phi_argument_bb
->phi_argument_defined_by_phi
->phi_variable_index
;
1903 } else if (phi_argument_bb
->phi_argument_defined_by_real_occurrence
!=NULL
) {
1904 phi_argument_variable_index
= phi_argument_bb
->phi_argument_defined_by_real_occurrence
->variable_index
;
1906 g_assert_not_reached ();
1909 phi
->inst_phi_args
[in_bb
+ 1] = phi_argument_variable_index
;
1911 store
= mono_compile_create_var_store (area
->cfg
, current_bb
->phi_variable_index
, phi
);
1912 if (current_bb
->phi_insertion_point
!= NULL
) {
1913 store
->next
= current_bb
->phi_insertion_point
->next
;
1914 current_bb
->phi_insertion_point
->next
= store
;
1916 store
->next
= current_bb
->bb
->code
;
1917 current_bb
->bb
->code
= store
;
1919 MONO_VARINFO (area
->cfg
, current_bb
->phi_variable_index
)->def
= store
;
1920 current_bb
->phi_insertion_point
= store
;
1922 area
->added_phis
++;
1925 for (current_expression
= current_bb
->first_expression_in_bb
; (current_expression
!= NULL
) && (current_expression
->bb_info
== current_bb
); current_expression
= current_expression
->next
) {
1926 gboolean altered
= FALSE
;
1927 if (current_expression
->save
) {
1929 MonoInst
*moved_expression
= mono_mempool_alloc (area
->cfg
->mempool
, sizeof (MonoInst
));
1930 *moved_expression
= *(current_expression
->occurrence
);
1931 store
= mono_compile_create_var_store (area
->cfg
, current_expression
->variable_index
, moved_expression
);
1932 if (current_expression
->previous_tree
!= NULL
) {
1933 store
->next
= current_expression
->previous_tree
->next
;
1934 current_expression
->previous_tree
->next
= store
;
1936 store
->next
= current_bb
->bb
->code
;
1937 current_bb
->bb
->code
= store
;
1939 MONO_VARINFO (area
->cfg
, current_expression
->variable_index
)->def
= store
;
1940 mono_compile_make_var_load (area
->cfg
, current_expression
->occurrence
, current_expression
->variable_index
);
1941 if (current_expression
->father_in_tree
!= NULL
) {
1942 handle_father_expression (area
, current_expression
, store
);
1945 area
->saved_occurrences
++;
1948 if (current_expression
->reload
) {
1949 gssize variable_index
;
1950 if (current_expression
->defined_by_phi
!= NULL
) {
1951 variable_index
= current_expression
->defined_by_phi
->phi_variable_index
;
1952 } else if (current_expression
->defined_by_real_occurrence
!= NULL
) {
1953 variable_index
= current_expression
->defined_by_real_occurrence
->variable_index
;
1955 variable_index
= BOTTOM_REDUNDANCY_CLASS
;
1956 g_assert_not_reached ();
1958 mono_compile_make_var_load (area
->cfg
, current_expression
->occurrence
, variable_index
);
1959 if (current_expression
->father_in_tree
!= NULL
) {
1960 handle_father_expression (area
, current_expression
, current_expression
->previous_tree
);
1963 area
->reloaded_occurrences
++;
1967 area
->unaltered_occurrences
++;
1971 if (current_bb
->phi_argument_variable_index
!= BOTTOM_REDUNDANCY_CLASS
) {
1972 MonoSsapreExpressionDescription expression_description
;
1973 MonoInst
*inserted_expression
;
1976 expression_description
= area
->current_expression
->description
;
1977 if (expression_description
.left_argument
.type
== MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE
) {
1978 expression_description
.left_argument
.argument
.ssa_variable
= current_bb
->phi_argument_left_argument_version
;
1979 expression_description
.left_argument
.type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
;
1981 if (expression_description
.right_argument
.type
== MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE
) {
1982 expression_description
.right_argument
.argument
.ssa_variable
= current_bb
->phi_argument_right_argument_version
;
1983 expression_description
.right_argument
.type
= MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE
;
1986 inserted_expression
= create_expression (area
, &expression_description
, &prototype_occurrence
);
1987 store
= mono_compile_create_var_store (area
->cfg
, current_bb
->phi_argument_variable_index
, inserted_expression
);
1988 MONO_VARINFO (area
->cfg
, current_bb
->phi_argument_variable_index
)->def
= store
;
1990 mono_add_ins_to_end (current_bb
->bb
, store
);
1992 area
->inserted_occurrences
++;
1998 * Perform all SSAPRE steps for the current expression
2001 process_expression (MonoSsapreWorkArea
*area
) {
2002 MonoSsapreExpression
*expression
= area
->current_expression
;
2004 if (area
->cfg
->verbose_level
>= STATISTICS_LEVEL
) {
2005 printf ("SSAPRE STARTS PROCESSING EXPRESSION ");
2006 print_expression_description (&(expression
->description
));
2010 clean_area_infos (area
);
2012 area
->current_expression
= expression
;
2013 phi_insertion (area
, expression
);
2014 renaming_pass (area
);
2016 if (area
->cfg
->verbose_level
>= TRACE_LEVEL
) {
2017 printf ("START SUMMARY OF BB INFOS\n");
2018 print_bb_infos (area
);
2019 printf ("END SUMMARY OF BB INFOS\n");
2023 compute_can_be_available (area
);
2024 compute_later (area
);
2025 if (finalize (area
)) {
2028 if (area
->cfg
->verbose_level
>= TRACE_LEVEL
) {
2029 printf ("SSAPRE CODE MOTION SKIPPED\n");
2034 if (area
->cfg
->verbose_level
>= DUMP_LEVEL
) {
2035 printf ("START DUMP OF BB INFOS\n");
2037 printf ("END DUMP OF BB INFOS\n");
2038 } else if (area
->cfg
->verbose_level
>= TRACE_LEVEL
) {
2039 printf ("START SUMMARY OF BB INFOS\n");
2040 print_interesting_bb_infos (area
);
2041 printf ("END SUMMARY OF BB INFOS\n");
2044 if (area
->cfg
->verbose_level
>= STATISTICS_LEVEL
) {
2045 printf ("STATISTICS: saved_occurrences = %d, reloaded_occurrences = %d, inserted_occurrences = %d, unaltered_occurrences = %d, added_phis = %d\n",
2046 area
->saved_occurrences
, area
->reloaded_occurrences
, area
->inserted_occurrences
, area
->unaltered_occurrences
, area
->added_phis
);
2049 if (area
->cfg
->verbose_level
>= TRACE_LEVEL
) {
2050 printf ("SSAPRE ENDS PROCESSING EXPRESSION ");
2051 print_expression_description (&(expression
->description
));
2056 #if (MONO_APPLY_SSAPRE_TO_SINGLE_METHOD)
2058 mono_ssapre_method_name
= NULL
;
2059 static gboolean
check_ssapre_method_name (MonoCompile
*cfg
) {
2060 if (mono_ssapre_method_name
== NULL
) {
2061 mono_ssapre_method_name
= getenv ("MONO_SSAPRE_METHOD_NAME");
2063 if (mono_ssapre_method_name
!= NULL
) {
2064 char *method_name
= mono_method_full_name (cfg
->method
, TRUE
);
2065 if (strstr (method_name
, mono_ssapre_method_name
) != NULL
) {
2077 * Apply SSAPRE to a MonoCompile
2080 mono_perform_ssapre (MonoCompile
*cfg
) {
2081 MonoSsapreWorkArea area
;
2082 int dt_dfn
, descendants
, block
, i
;
2084 #if (MONO_APPLY_SSAPRE_TO_SINGLE_METHOD)
2085 if (! check_ssapre_method_name (cfg
)) return;
2087 #if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
2088 area
.expression_is_handled_father
= FALSE
;
2092 area
.mempool
= mono_mempool_new ();
2094 area
.num_bblocks
= cfg
->num_bblocks
;
2095 area
.bb_infos
= (MonoSsapreBBInfo
*) mono_mempool_alloc (area
.mempool
, sizeof (MonoSsapreBBInfo
) * (cfg
->num_bblocks
));
2096 area
.bb_infos_in_cfg_dfn_order
= (MonoSsapreBBInfo
**) mono_mempool_alloc (area
.mempool
, sizeof (MonoSsapreBBInfo
*) * (cfg
->num_bblocks
));
2098 area
.sizeof_bb_bitset
= mono_bitset_alloc_size (cfg
->num_bblocks
, 0);
2099 area
.expression_occurrences_buffer
= mono_bitset_mem_new (mono_mempool_alloc (area
.mempool
, area
.sizeof_bb_bitset
), area
.num_bblocks
, 0);
2100 area
.bb_iteration_buffer
= mono_bitset_mem_new (mono_mempool_alloc (area
.mempool
, area
.sizeof_bb_bitset
), area
.num_bblocks
, 0);
2101 area
.iterated_dfrontier_buffer
= mono_bitset_mem_new (mono_mempool_alloc (area
.mempool
, area
.sizeof_bb_bitset
), area
.num_bblocks
, 0);
2102 area
.left_argument_bb_bitset
= mono_bitset_mem_new (mono_mempool_alloc (area
.mempool
, area
.sizeof_bb_bitset
), area
.num_bblocks
, 0);
2103 area
.right_argument_bb_bitset
= mono_bitset_mem_new (mono_mempool_alloc (area
.mempool
, area
.sizeof_bb_bitset
), area
.num_bblocks
, 0);
2105 area
.worklist
= NULL
;
2107 if (area
.cfg
->verbose_level
>= LOG_LEVEL
) {
2108 printf ("SSAPRE STARTS PROCESSING METHOD %s\n", mono_method_full_name (cfg
->method
, TRUE
));
2110 if (area
.cfg
->verbose_level
>= DUMP_LEVEL
) {
2111 mono_print_code (area
.cfg
, "BEFORE SSAPRE");
2114 area
.first_in_queue
= NULL
;
2115 area
.last_in_queue
= NULL
;
2116 area
.current_occurrence
= (MonoSsapreExpressionOccurrence
*) mono_mempool_alloc (area
.mempool
, sizeof (MonoSsapreExpressionOccurrence
));
2120 process_bb (&area
, cfg
->bblocks
[0], &dt_dfn
, &descendants
, 1);
2121 for (block
= 0; block
< area
.num_bblocks
; block
++) {
2122 MonoSsapreBBInfo
*bb_info
= &(area
.bb_infos
[block
]);
2123 MonoBasicBlock
*bb
= bb_info
->bb
;
2124 if (bb
->idom
!= NULL
) {
2125 bb_info
->idominator
= area
.bb_infos_in_cfg_dfn_order
[bb
->idom
->dfn
];
2127 bb_info
->idominator
= NULL
;
2129 for (i
= 0; i
< bb
->in_count
; i
++) {
2130 bb_info
->in_bb
[i
] = area
.bb_infos_in_cfg_dfn_order
[bb
->in_bb
[i
]->dfn
];
2132 for (i
= 0; i
< bb
->out_count
; i
++) {
2133 bb_info
->out_bb
[i
] = area
.bb_infos_in_cfg_dfn_order
[bb
->out_bb
[i
]->dfn
];
2137 if (area
.cfg
->verbose_level
>= TRACE_LEVEL
) {
2138 printf ("SSAPRE START WORKLIST\n");
2139 print_worklist (area
.worklist
);
2140 printf ("SSAPRE END WORKLIST\n");
2143 #if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
2144 area
.expression_is_handled_father
= TRUE
;
2146 for (area
.current_expression
= area
.first_in_queue
; area
.current_expression
!= NULL
; area
.current_expression
= area
.current_expression
->next_in_queue
) {
2147 process_expression (&area
);
2150 if (area
.cfg
->verbose_level
>= DUMP_LEVEL
) {
2151 mono_print_code (area
.cfg
, "AFTER SSAPRE");
2153 if (area
.cfg
->verbose_level
>= TRACE_LEVEL
) {
2154 printf ("SSAPRE ENDS PROCESSING METHOD %s\n", mono_method_full_name (cfg
->method
, TRUE
));
2157 mono_mempool_destroy (area
.mempool
);
2160 #endif /* DISABLE_SSA */
2165 mono_perform_ssapre (MonoCompile
*cfg
)