Pinvoke symbols according to the new moonlight naming convention.
[mono-project.git] / mono / mini / ssapre.c
blobdf1eaff9f4852e6dee6ae48699ab66d249e76d5b
1 /*
2 * ssapre.h: SSA Partial Redundancy Elimination
4 * Author:
5 * Massimiliano Mantione (massi@ximian.com)
7 * (C) 2004 Novell, Inc. http://www.novell.com
8 */
10 #include <string.h>
11 #include <stdio.h>
12 #include <math.h>
13 #ifdef HAVE_ALLOCA_H
14 #include <alloca.h>
15 #endif
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/metadata/opcodes.h>
20 #include "config.h"
22 #include "ssapre.h"
24 /* Disable for now to save space since it is not yet ported to linear IR */
25 #if 0
27 #ifndef DISABLE_SSA
29 /* Logging conditions */
30 #define DUMP_LEVEL (4)
31 #define TRACE_LEVEL (3)
32 #define STATISTICS_LEVEL (2)
33 #define LOG_LEVEL (1)
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... */
43 static void
44 print_argument (MonoSsapreExpressionArgument *argument) {
45 switch (argument->type) {
46 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY:
47 printf ("ANY");
48 break;
49 case MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT:
50 printf ("NONE");
51 break;
52 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE:
53 printf ("ORIGINAL_VARIABLE %d", argument->argument.original_variable);
54 break;
55 case MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE:
56 printf ("SSA_VARIABLE %d", argument->argument.ssa_variable);
57 break;
58 case MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT:
59 printf ("INTEGER_CONSTANT %d", argument->argument.integer_constant);
60 break;
61 case MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT:
62 printf ("LONG_COSTANT %lld", (long long)*(argument->argument.long_constant));
63 break;
64 case MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT:
65 printf ("FLOAT_COSTANT %f", *(argument->argument.float_constant));
66 break;
67 case MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT:
68 printf ("DOUBLE_COSTANT %f", *(argument->argument.double_constant));
69 break;
70 default:
71 printf ("UNKNOWN: %d", argument->type);
76 static void
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));
81 printf ("],[");
82 print_argument (&(expression_description->right_argument));
83 printf ("])");
84 } else {
85 printf ("ANY");
89 #if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
90 static void
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");
95 break;
96 case MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT:
97 g_string_append_printf (string, "NONE");
98 break;
99 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE:
100 g_string_append_printf (string, "ORIGINAL_VARIABLE %d", argument->argument.original_variable);
101 break;
102 case MONO_SSAPRE_EXPRESSION_ARGUMENT_SSA_VARIABLE:
103 g_string_append_printf (string, "SSA_VARIABLE %d", argument->argument.ssa_variable);
104 break;
105 case MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT:
106 g_string_append_printf (string, "INTEGER_CONSTANT %d", argument->argument.integer_constant);
107 break;
108 case MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT:
109 g_string_append_printf (string, "LONG_COSTANT %lld", *(argument->argument.long_constant));
110 break;
111 case MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT:
112 g_string_append_printf (string, "FLOAT_COSTANT %f", *(argument->argument.float_constant));
113 break;
114 case MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT:
115 g_string_append_printf (string, "DOUBLE_COSTANT %f", *(argument->argument.double_constant));
116 break;
117 default:
118 g_string_append_printf (string, "UNKNOWN: %d", argument->type);
122 static void
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, "])");
130 } else {
131 g_string_append_printf (string, "ANY");
134 #endif
136 #define GBOOLEAN_TO_STRING(b) ((b)?"TRUE":"FALSE")
138 static void
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));
150 printf ("\n");
151 occurrence = occurrence->next;
154 static void
155 print_expression_occurrences (MonoSsapreExpressionOccurrence *occurrences) {
156 int i = 0;
157 while (occurrences != NULL) {
158 i++;
159 print_expression_occurrence (occurrences, i);
160 occurrences = occurrences->next;
164 static void
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));
171 printf ("\n");
172 print_expression_occurrences (expression->occurrences);
174 print_worklist (expression->next);
178 static void
179 print_bb_info (MonoSsapreBBInfo *bb_info, gboolean print_occurrences) {
180 int i;
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);
187 printf ("}, OUT {");
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);
191 printf ("}");
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)");
197 } else {
198 printf (" (NEVER DOWN SAFE)");
200 printf ("\n");
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);
207 } else {
208 printf ("BOTTOM ");
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) {
216 i = 0;
217 while ((current_occurrence != NULL) && (current_occurrence->bb_info == bb_info)) {
218 print_expression_occurrence (current_occurrence, i);
219 current_occurrence = current_occurrence->next;
220 i++;
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);
227 } else {
228 printf ("BOTTOM ");
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);
234 } else {
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);
240 } else {
241 printf ("NONE ");
243 printf (", right ");
244 if (bb_info->phi_argument_right_argument_version != BOTTOM_REDUNDANCY_CLASS) {
245 printf ("%d ", bb_info->phi_argument_right_argument_version);
246 } else {
247 printf ("NONE ");
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));
255 static void
256 print_bb_infos (MonoSsapreWorkArea *area) {
257 int i;
258 for (i = 0; i < area->num_bblocks; i++) {
259 MonoSsapreBBInfo *bb_info = &(area->bb_infos [i]);
260 print_bb_info (bb_info, TRUE);
264 static void
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) {
274 int i;
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.
291 static void
292 analyze_argument (MonoInst *argument, MonoSsapreExpressionArgument *result) {
293 switch (argument->opcode) {
294 case CEE_LDIND_I1:
295 case CEE_LDIND_U1:
296 case CEE_LDIND_I2:
297 case CEE_LDIND_U2:
298 case CEE_LDIND_I4:
299 case CEE_LDIND_U4:
300 case CEE_LDIND_I8:
301 case CEE_LDIND_I:
302 case CEE_LDIND_R4:
303 case CEE_LDIND_R8:
304 case CEE_LDIND_REF:
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;
308 } else {
309 result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
311 break;
312 case OP_ICONST:
313 result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT;
314 result->argument.integer_constant = argument->inst_c0;
315 break;
316 case OP_I8CONST:
317 result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT;
318 result->argument.long_constant = &(argument->inst_l);
319 break;
320 case OP_R4CONST:
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;
324 } else {
325 result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
327 break;
328 case OP_R8CONST:
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;
332 } else {
333 result->type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
335 break;
336 default:
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.
346 static void
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"
352 #undef OPDEF
353 #define MINI_OP(a1,a2) case a1:
354 #include "simple-mini-ops.h"
355 #undef MINI_OP
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));
367 } else {
368 result->right_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT;
370 } else {
371 result->opcode = 0;
373 } else {
374 result->opcode = 0;
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);
378 //~ } else {
379 //~ printf ("SSAPRE cannot really handle expression of opcode %s (%d)\n", mono_inst_name (expression->opcode), expression->opcode);
380 //~ }
382 break;
383 default:
384 result->opcode = 0;
385 result->left_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
386 result->right_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
388 //~ switch (expression->opcode) {
389 //~ case CEE_ADD:
390 //~ if ((result->left_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT) &&
391 //~ (result->right_argument.type != MONO_SSAPRE_EXPRESSION_ARGUMENT_INTEGER_CONSTANT)) {
392 //~ break;
393 //~ }
394 //~ case CEE_LDELEMA:
395 //~ case CEE_LDLEN:
396 //~ result->opcode = 0;
397 //~ result->left_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
398 //~ result->right_argument.type = MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY;
399 //~ }
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").
410 static void
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;
417 } else {
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;
422 } else {
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;
428 } else {
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;
433 } else {
434 result->right_argument.argument.original_variable = expression->right_argument.argument.ssa_variable;
440 * Given a MonoInst, checks if it is a phi definition.
442 static gboolean
443 is_phi_definition (MonoInst *definition) {
444 if (definition != NULL) {
445 switch (definition->opcode) {
446 case CEE_STIND_REF:
447 case CEE_STIND_I:
448 case CEE_STIND_I4:
449 case CEE_STIND_I1:
450 case CEE_STIND_I2:
451 case CEE_STIND_I8:
452 case CEE_STIND_R4:
453 case CEE_STIND_R8:
454 if ((definition->inst_left->opcode == OP_LOCAL) &&
455 (definition->inst_right->opcode == OP_PHI)) {
456 return TRUE;
457 } else {
458 return FALSE;
460 default:
461 return FALSE;
463 } else {
464 return FALSE;
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.
479 static int*
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;
484 } else {
485 return NULL;
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];
500 } else {
501 return area->bb_infos;
506 * Given:
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.
515 static gssize
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];
521 } else {
522 return variable;
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
529 * autobalancing).
531 static MonoSsapreExpression*
532 add_expression_to_tree (MonoSsapreExpression *tree, MonoSsapreExpression *expression) {
533 MonoSsapreExpression *subtree;
534 MonoSsapreExpression **subtree_reference;
535 int comparison;
536 gssize max_tree_depth, max_subtree_size;
538 if (tree == NULL) {
539 expression->previous = NULL;
540 expression->next = NULL;
541 expression->tree_size = 1;
542 return expression;
545 tree->tree_size++;
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);
552 } else {
553 tree->next = expression;
554 expression->father = tree;
555 expression->previous = NULL;
556 expression->next = NULL;
557 expression->tree_size = 1;
558 return tree;
560 } else if (comparison < 0) {
561 if (tree->previous != NULL) {
562 subtree = tree->previous;
563 subtree_reference = &(tree->previous);
564 } else {
565 tree->previous = expression;
566 expression->father = tree;
567 expression->previous = NULL;
568 expression->next = NULL;
569 expression->tree_size = 1;
570 return tree;
572 } else {
573 g_assert_not_reached ();
574 return NULL;
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;
583 return tree;
584 } else {
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);
602 } else {
603 g_assert_not_reached ();
604 return NULL;
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;
617 } else {
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);
630 } else {
631 g_assert_not_reached ();
632 return NULL;
634 border_expression->tree_size = 1 + border_expression->previous->tree_size + border_expression->next->tree_size;
635 return border_expression;
636 } else {
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);
643 } else {
644 g_assert_not_reached ();
645 return NULL;
647 expression->tree_size = 1 + expression->previous->tree_size + expression->next->tree_size;
648 return expression;
653 #if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
654 static char *mono_ssapre_expression_name = NULL;
655 static gboolean
656 check_ssapre_expression_name (MonoSsapreWorkArea *area, MonoSsapreExpressionDescription *expression_description) {
657 if (area->expression_is_handled_father) {
658 return TRUE;
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) {
668 return_value = TRUE;
669 } else {
670 return_value = FALSE;
672 g_string_free (expression_name, TRUE);
673 return return_value;
674 } else {
675 return TRUE;
678 #endif
681 * Adds an expression to the worklist (putting the current occurrence as first
682 * occurrence of this expression).
684 static void
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;
693 #endif
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;
701 } else {
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.
715 static void
716 add_occurrence_to_worklist (MonoSsapreWorkArea *area) {
717 MonoSsapreExpressionDescription description;
718 MonoSsapreExpression *current_expression;
719 int comparison;
721 convert_ssa_variables_to_original_names (&description, &(area->current_occurrence->description), area->cfg);
722 current_expression = area->worklist;
724 do {
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;
732 } else {
733 MONO_SSAPRE_ADD_EXPRESSION_OCCURRANCE (current_expression, area->current_occurrence);
735 } else {
736 add_expression_to_worklist (area);
737 comparison = 0;
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.
747 static void
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;
772 if (DUMP_SSAPRE) {
773 printf ("Expression '");
774 mono_print_tree (inst);
775 printf ("' is a potential father ( ");
776 if (left_father_in_tree != NULL) {
777 printf ("LEFT ");
779 if (right_father_in_tree != NULL) {
780 printf ("RIGHT ");
782 printf (")\n");
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);
796 } else {
797 *father_in_tree = NULL;
799 } else {
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).
810 static void
811 process_bb (MonoSsapreWorkArea *area, MonoBasicBlock *bb, int *dt_dfn, int *upper_descendants, int current_depth) {
812 MonoSsapreBBInfo *bb_info;
813 int descendants;
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;
821 (*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;
827 bb_info->bb = bb;
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) {
839 case CEE_STIND_REF:
840 case CEE_STIND_I:
841 case CEE_STIND_I4:
842 case CEE_STIND_I1:
843 case CEE_STIND_I2:
844 case CEE_STIND_I8:
845 case CEE_STIND_R4:
846 case CEE_STIND_R8:
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;
857 break;
858 default:
859 break;
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;
879 descendants = 0;
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.
890 static void
891 clean_bb_infos (MonoSsapreWorkArea *area) {
892 int i;
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.
923 static void
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.
942 static void
943 compute_combined_dfrontier (MonoSsapreWorkArea *area, MonoBitSet* result, MonoBitSet *bblocks)
945 int i;
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.
955 static void
956 compute_combined_iterated_dfrontier (MonoSsapreWorkArea *area, MonoBitSet *result, MonoBitSet *bblocks, MonoBitSet *buffer)
958 gboolean change = TRUE;
960 compute_combined_dfrontier (area, result, bblocks);
961 do {
962 change = FALSE;
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);
968 change = TRUE;
970 } while (change);
974 * See paper, section 5.1, definition of "Dominate"
976 static gboolean
977 dominates (MonoSsapreBBInfo *dominator, MonoSsapreBBInfo *dominated) {
978 if ((dominator->dt_dfn <= dominated->dt_dfn) && (dominated->dt_dfn <= (dominator->dt_dfn + dominator->dt_descendants))) {
979 return TRUE;
980 } else {
981 return FALSE;
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)) {
994 int i;
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
1006 static void
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;
1013 int top;
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;
1033 } else {
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;
1055 top = -1;
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;
1068 } else {
1069 area->first_interesting_bb = current_bb;
1071 previous_interesting_bb = current_bb;
1072 } else {
1073 current_bb_is_interesting = FALSE;
1076 if (top >= 0) {
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;
1084 top--;
1086 } else {
1087 top = -1;
1090 top++;
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;
1096 } else {
1097 stack [top]->dt_covered_by_interesting_BBs = TRUE;
1100 while (top > 0) {
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;
1107 top--;
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; \
1119 } else { \
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; \
1125 } while(0)
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; \
1138 } while(0)
1141 * See paper, section 5.4.
1142 * The two passes are coded sequentially (no separate "rename1" and "rename2" functions).
1144 static void
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)) {
1163 if (TRACE_SSAPRE) {
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;
1173 } else {
1174 area->top_of_renaming_stack = NULL;
1176 area->bb_on_top_of_renaming_stack = top_bb->next_in_renaming_stack;
1178 if (DUMP_SSAPRE) {
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);
1185 } else {
1186 printf ("BOTTOM\n");
1189 } else {
1190 /* With no backtracking we just propagate the flag */
1191 current_bb->phi_argument_has_real_use = previous_bb->phi_argument_has_real_use;
1193 } else {
1194 /* Start condition */
1195 current_bb->phi_argument_has_real_use = FALSE;
1197 if (DUMP_SSAPRE) {
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;
1205 } else {
1206 current_bb->phi_is_down_safe = FALSE;
1208 current_bb->phi_redundancy_class = current_class;
1209 current_class++;
1210 PUSH_PHI_OCCURRENCE (current_bb);
1211 if (TRACE_SSAPRE) {
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;
1227 if (DUMP_SSAPRE) {
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);
1232 } else {
1233 current_expression->redundancy_class = current_class;
1234 current_class++;
1235 current_expression->defined_by_real_occurrence = NULL;
1236 PUSH_REAL_OCCURRENCE (current_expression);
1237 if (TRACE_SSAPRE) {
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) {
1264 int phi_argument;
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) {
1275 if (DUMP_SSAPRE) {
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);
1299 if (DUMP_SSAPRE) {
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);
1304 } else {
1305 current_expression->redundancy_class = current_class;
1306 current_class++;
1307 current_expression->defined_by_phi = NULL;
1308 PUSH_REAL_OCCURRENCE (current_expression);
1309 phi_bb->phi_is_down_safe = FALSE;
1310 if (TRACE_SSAPRE) {
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;
1319 } else {
1320 current_expression->redundancy_class = current_class;
1321 current_class++;
1322 current_expression->defined_by_real_occurrence = NULL;
1323 current_expression->defined_by_phi = NULL;
1324 PUSH_REAL_OCCURRENCE (current_expression);
1325 if (TRACE_SSAPRE) {
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;
1340 } else {
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)) {
1350 if (TRACE_SSAPRE) {
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;
1385 } else {
1386 current_bb->phi_argument_class = BOTTOM_REDUNDANCY_CLASS;
1388 } else {
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)) {
1394 if (TRACE_SSAPRE) {
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;
1402 if (DUMP_SSAPRE) {
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) {
1413 int i;
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
1427 static void
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)) {
1430 int i;
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
1442 static void
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) {
1449 int i;
1450 for (i = 0; i < current_bb->in_count; i++) {
1451 reset_down_safe (current_bb->in_bb [i]);
1459 * See paper, figure 10
1461 static void
1462 reset_can_be_available (MonoSsapreWorkArea *area, MonoSsapreBBInfo *phi) {
1463 MonoSsapreBBInfo *current_bb = NULL;
1465 if (DUMP_SSAPRE) {
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;
1474 int i;
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;
1480 break;
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
1494 static void
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;
1502 int i;
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;
1507 break;
1511 if (phi_is_interesting) {
1512 if (DUMP_SSAPRE) {
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
1526 static void
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;
1535 int i;
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;
1541 break;
1545 if (phi_is_interesting) {
1546 reset_later (area, current_bb);
1554 * See paper, figure 10
1556 static void
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;
1569 int i;
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;
1575 break;
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)) {
1612 defining_bb = NULL;
1616 if (defining_bb == NULL) {
1617 current_expression->reload = FALSE;
1618 availability_table [current_expression->redundancy_class].class_defined_by_real_occurrence = current_expression;
1619 } else {
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)))
1637 ))) {
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;
1647 } else {
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) {
1667 int i;
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));
1713 int i;
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))) {
1724 return FALSE;
1725 } else {
1726 finalize_save (area);
1727 return TRUE;
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); \
1737 } while (0)
1739 #define NEW_I4(dest,val) do { \
1740 NEW_INST ((dest), OP_ICONST); \
1741 (dest)->inst_c0 = (val); \
1742 (dest)->type = STACK_I4; \
1743 } while (0)
1745 #define NEW_I8(dest,val) do { \
1746 NEW_INST ((dest), OP_I8CONST); \
1747 (dest)->inst_l = (val); \
1748 (dest)->type = STACK_I8; \
1749 } while (0)
1751 #define NEW_R4(dest,f) do { \
1752 NEW_INST ((dest), OP_R4CONST); \
1753 (dest)->inst_p0 = f; \
1754 (dest)->type = STACK_R8; \
1755 } while (0)
1757 #define NEW_R8(dest,d) do { \
1758 NEW_INST ((dest), OP_R8CONST); \
1759 (dest)->inst_p0 = d; \
1760 (dest)->type = STACK_R8; \
1761 } while (0)
1764 * Create a MonoInst that represents an expression argument
1766 static MonoInst*
1767 create_expression_argument (MonoSsapreWorkArea *area, MonoSsapreExpressionArgument *argument) {
1768 MonoInst *result;
1770 switch (argument->type) {
1771 case MONO_SSAPRE_EXPRESSION_ARGUMENT_NOT_PRESENT:
1772 return NULL;
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);
1777 return result;
1778 case MONO_SSAPRE_EXPRESSION_ARGUMENT_LONG_COSTANT:
1779 NEW_I8 (result, *(argument->argument.long_constant));
1780 return result;
1781 case MONO_SSAPRE_EXPRESSION_ARGUMENT_FLOAT_COSTANT:
1782 NEW_R4 (result, argument->argument.float_constant);
1783 return result;
1784 case MONO_SSAPRE_EXPRESSION_ARGUMENT_DOUBLE_COSTANT:
1785 NEW_R8 (result, argument->argument.double_constant);
1786 return result;
1787 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ORIGINAL_VARIABLE:
1788 case MONO_SSAPRE_EXPRESSION_ARGUMENT_ANY:
1789 default:
1790 g_assert_not_reached ();
1791 return NULL;
1796 * Create a MonoInst that represents an expression
1798 static MonoInst*
1799 create_expression (MonoSsapreWorkArea *area, MonoSsapreExpressionDescription *expression, MonoInst *prototype_occurrence) {
1800 MonoInst *result;
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));
1805 return result;
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".
1813 static void
1814 handle_father_expression (MonoSsapreWorkArea *area, MonoSsapreExpressionOccurrence *current_expression, MonoInst *previous_tree) {
1815 if (DUMP_SSAPRE) {
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;
1853 } else {
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;
1869 } else {
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;
1882 } else {
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) {
1889 MonoInst *phi;
1890 MonoInst *store;
1891 int in_bb;
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;
1905 } else {
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;
1915 } else {
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) {
1928 MonoInst *store;
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;
1935 } else {
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 ++;
1946 altered = TRUE;
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;
1954 } else {
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 ++;
1964 altered = TRUE;
1966 if (! altered) {
1967 area->unaltered_occurrences ++;
1971 if (current_bb->phi_argument_variable_index != BOTTOM_REDUNDANCY_CLASS) {
1972 MonoSsapreExpressionDescription expression_description;
1973 MonoInst *inserted_expression;
1974 MonoInst *store;
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;
1989 store->next = NULL;
1990 mono_add_ins_to_end (current_bb->bb, store);
1992 area->inserted_occurrences ++;
1998 * Perform all SSAPRE steps for the current expression
2000 static void
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));
2007 printf ("\n");
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");
2022 down_safety (area);
2023 compute_can_be_available (area);
2024 compute_later (area);
2025 if (finalize (area)) {
2026 code_motion (area);
2027 } else {
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");
2036 dump_code (area);
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));
2052 printf ("\n");
2056 #if (MONO_APPLY_SSAPRE_TO_SINGLE_METHOD)
2057 static char*
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) {
2066 return TRUE;
2067 } else {
2068 return FALSE;
2070 } else {
2071 return TRUE;
2074 #endif
2077 * Apply SSAPRE to a MonoCompile
2079 void
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;
2086 #endif
2087 #if (MONO_APPLY_SSAPRE_TO_SINGLE_EXPRESSION)
2088 area.expression_is_handled_father = FALSE;
2089 #endif
2091 area.cfg = cfg;
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));
2117 dt_dfn = 0;
2118 descendants = 0;
2119 area.dt_depth = 0;
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];
2126 } else {
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;
2145 #endif
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 */
2162 #else /* 0 */
2164 void
2165 mono_perform_ssapre (MonoCompile *cfg)
2169 #endif /* 0 */