#include "tree-ssa-live.h"
#include "tree-ssa-coalesce.h"
#include "diagnostic-core.h"
+#include "timevar.h"
/* This set of routines implements a coalesce_list. This is an object which
/* Attempt to coalesce ssa versions X and Y together using the partition
- mapping in MAP and checking conflicts in GRAPH. Output any debug info to
- DEBUG, if it is nun-NULL. */
+ mapping in MAP and checking conflicts in GRAPH if not NULL.
+ Output any debug info to DEBUG, if it is nun-NULL. */
static inline bool
attempt_coalesce (var_map map, ssa_conflicts_p graph, int x, int y,
fprintf (debug, " [map: %d, %d] ", p1, p2);
- if (!ssa_conflicts_test_p (graph, p1, p2))
+ if (!graph
+ || !ssa_conflicts_test_p (graph, p1, p2))
{
var1 = partition_to_var (map, p1);
var2 = partition_to_var (map, p2);
/* z is the new combined partition. Remove the other partition from
the list, and merge the conflicts. */
- if (z == p1)
- ssa_conflicts_merge (graph, p1, p2);
- else
- ssa_conflicts_merge (graph, p2, p1);
+ if (graph)
+ {
+ if (z == p1)
+ ssa_conflicts_merge (graph, p1, p2);
+ else
+ ssa_conflicts_merge (graph, p2, p1);
+ }
if (debug)
fprintf (debug, ": Success -> %d\n", z);
}
-/* Attempt to Coalesce partitions in MAP which occur in the list CL using
- GRAPH. Debug output is sent to DEBUG if it is non-NULL. */
+/* Perform all abnormal coalescing on MAP.
+ Debug output is sent to DEBUG if it is non-NULL. */
static void
-coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
- FILE *debug)
+perform_abnormal_coalescing (var_map map, FILE *debug)
{
- int x = 0, y = 0;
- tree var1, var2;
- int cost;
basic_block bb;
edge e;
edge_iterator ei;
- /* First, coalesce all the copies across abnormal edges. These are not placed
- in the coalesce list because they do not need to be sorted, and simply
- consume extra memory/compilation time in large programs. */
-
FOR_EACH_BB_FN (bb, cfun)
{
FOR_EACH_EDGE (e, ei, bb->preds)
if (debug)
fprintf (debug, "Abnormal coalesce: ");
- if (!attempt_coalesce (map, graph, v1, v2, debug))
+ if (!attempt_coalesce (map, NULL, v1, v2, debug))
fail_abnormal_edge_coalesce (v1, v2);
}
}
}
+}
+
+/* Attempt to Coalesce partitions in MAP which occur in the list CL using
+ GRAPH. Debug output is sent to DEBUG if it is non-NULL. */
+
+static void
+coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
+ FILE *debug)
+{
+ int x = 0, y = 0;
+ tree var1, var2;
+ int cost;
/* Now process the items in the coalesce list. */
var_map map;
unsigned int i;
+#ifdef ENABLE_CHECKING
+ /* Verify we can perform all must coalesces. */
+ verify_ssa_coalescing ();
+#endif
+
cl = create_coalesce_list ();
map = create_outofssa_var_map (cl, used_in_copies);
return map;
}
+ /* First, coalesce all the copies across abnormal edges. These are not placed
+ in the coalesce list because they do not need to be sorted, and simply
+ consume extra memory/compilation time in large programs.
+ Performing abnormal coalescing also needs no live/conflict computation
+ because it must succeed (but we lose checking that it indeed does).
+ Still for PR63155 this reduces memory usage from 10GB to zero. */
+ perform_abnormal_coalescing (map,
+ ((dump_flags & TDF_DETAILS) ? dump_file : NULL));
+
if (dump_file && (dump_flags & TDF_DETAILS))
dump_var_map (dump_file, map);
/* Now coalesce everything in the list. */
coalesce_partitions (map, graph, cl,
- ((dump_flags & TDF_DETAILS) ? dump_file
- : NULL));
+ ((dump_flags & TDF_DETAILS) ? dump_file : NULL));
delete_coalesce_list (cl);
ssa_conflicts_delete (graph);
return map;
}
+
+
+/* Helper for verify_ssa_coalescing. Operates in two modes:
+ 1) scan the function for coalesces we must perform and store the
+ SSA names participating in USED_IN_COPIES
+ 2) scan the function for coalesces and verify they can be performed
+ under the constraints of GRAPH updating MAP in the process
+ FIXME: This can be extended to verify that the virtual operands
+ form a factored use-def chain (coalescing the active virtual use
+ with the virtual def at virtual def point). */
+
+static void
+verify_ssa_coalescing_worker (bitmap used_in_copies,
+ var_map map, ssa_conflicts_p graph)
+{
+ basic_block bb;
+
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ edge e;
+ edge_iterator ei;
+
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ if (e->flags & EDGE_ABNORMAL)
+ {
+ gphi_iterator gsi;
+ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gphi *phi = gsi.phi ();
+ tree arg = PHI_ARG_DEF (phi, e->dest_idx);
+ if (SSA_NAME_IS_DEFAULT_DEF (arg)
+ && (!SSA_NAME_VAR (arg)
+ || TREE_CODE (SSA_NAME_VAR (arg)) != PARM_DECL))
+ continue;
+
+ tree res = PHI_RESULT (phi);
+
+ int v1 = SSA_NAME_VERSION (res);
+ int v2 = SSA_NAME_VERSION (arg);
+ if (used_in_copies)
+ {
+ bitmap_set_bit (used_in_copies, v1);
+ bitmap_set_bit (used_in_copies, v2);
+ }
+ else
+ {
+ int p1 = var_to_partition (map, res);
+ int p2 = var_to_partition (map, arg);
+ if (p1 != p2)
+ {
+ if (ssa_conflicts_test_p (graph, p1, p2))
+ fail_abnormal_edge_coalesce (v1, v2);
+ int z = var_union (map,
+ partition_to_var (map, p1),
+ partition_to_var (map, p2));
+ if (z == p1)
+ ssa_conflicts_merge (graph, p1, p2);
+ else
+ ssa_conflicts_merge (graph, p2, p1);
+ }
+ }
+ }
+ }
+ }
+}
+
+/* Verify that we can coalesce SSA names we must coalesce. */
+
+DEBUG_FUNCTION void
+verify_ssa_coalescing (void)
+{
+ auto_timevar tv (TV_TREE_SSA_VERIFY);
+ bitmap used_in_copies = BITMAP_ALLOC (NULL);
+ verify_ssa_coalescing_worker (used_in_copies, NULL, NULL);
+ if (bitmap_empty_p (used_in_copies))
+ {
+ BITMAP_FREE (used_in_copies);
+ return;
+ }
+ var_map map = init_var_map (num_ssa_names);
+ partition_view_bitmap (map, used_in_copies, true);
+ BITMAP_FREE (used_in_copies);
+ tree_live_info_p liveinfo = calculate_live_ranges (map, false);
+ ssa_conflicts_p graph = build_ssa_conflict_graph (liveinfo);
+ delete_tree_live_info (liveinfo);
+ verify_ssa_coalescing_worker (NULL, map, graph);
+ ssa_conflicts_delete (graph);
+ delete_var_map (map);
+}