On Sat, Mar 28, 2015 at 8:21 PM, Alexandre Oliva <aol...@redhat.com> wrote: > On Mar 27, 2015, Alexandre Oliva <aol...@redhat.com> wrote: > >> This patch reworks the out-of-ssa expander to enable coalescing of SSA >> partitions that don't share the same base name. This is done only when >> optimizing. > >> The test we use to tell whether two partitions can be merged no longer >> demands them to have the same base variable when optimizing, so they >> become eligible for coalescing, as they would after copyrename. We then >> compute the partitioning we'd get if all coalescible partitions were >> coalesced, using this partition assignment to assign base vars numbers. >> These base var numbers are then used to identify conflicts, which used >> to be based on shared base vars or base types. > >> We now propagate base var names during coalescing proper, only towards >> the leader variable. I'm no longer sure this is still needed, but >> something about handling variables and results led me this way and I >> didn't revisit it. I might rework that with a later patch, or a later >> revision of this patch; it would require other means to identify >> partitions holding result_decls during merging, or allow that and deal >> with param and result decls in a different way during expand proper. > >> I had to fix two lingering bugs in order for the whole thing to work: we >> perform conflict detection after abnormal coalescing, but we computed >> live ranges involving only the partition leaders, so conflicts with >> other names already coalesced wouldn't be detected. > > This early abnormal coalescing was only present for a few days in the > trunk, and I was lucky enough to start working on a tree that had it. > It turns out that the fix for it was thus rendered unnecessary, so I > dropped it. It was the fix for it, that didn't cover the live range > check, that caused the two ICEs I saw in the regressions tests. Since > the ultimate cause of the problem is gone, and the change that > introduced the check failures, both problems went *poof* after I updated > the tree, resolved the conflicts and dropped the redundant code. > >> The other problem was that we didn't track default defs for parms as >> live at entry, so they might end up coalesced. > > I improved this a little bit, using the bitmap of partitions containing > default params to check that we only process function-entry defs for > them, rather than for all param decls in case they end up in other > partitions. > >> I guess none of these problems would have been exercised in practice, >> because we wouldn't even consider merging ssa names associated with >> different variables. > >> In the end, I verified that this fixed the codegen regression in the >> PR64164 testcase, that failed to merge two partitions that could in >> theory be merged, but that wasn't even considered due to differences in >> the SSA var names. > >> I'd agree that disregarding the var names and dropping 4 passes is too >> much of a change to fix this one problem, but... it's something we >> should have long tackled, and it gets this and other jobs done, so... > > Regstrapped on x86_64-linux-gnu native and on i686-pc-linux-gnu native > on x86_64, so without lto plugin. The only regression is in > gcc.dg/guality/pr54200.c, that explicitly disables VTA. When > optimization is enabled, the different coalescing we perform now causes > VTA-less variable tracking to lose track of variable "z". This > regression in non-VTA var-tracking is expected and, as richi put it in > PR 64164, I guess we don't care about that, do we? :-)
Apart from at -O0, yes. > The other guality regressions I mentioned in my other email turned out > not to be regressions, but preexisting failures that somehow did not > make to the test_summary of my earlier pristine build. > > Is this ok to install? I think this is stage1 material. Some comments in-line > > for gcc/ChangeLog > > PR rtl-optimization/64164 > * Makefile.in (OBJS): Drop tree-ssa-copyrename.o. > * tree-ssa-copyrename.c: Removed. > * opts.c (default_options_table): Drop -ftree-copyrename. > * passes.def: Drop all occurrences of pass_rename_ssa_copies. > * common.opt (ftree-copyrename): Ignore. > (ftree-coalesce-vars, ftree-coalesce-inlined-vars): Likewise. > * doc/invoke.texi: Remove the ignored options above. > * gimple-expr.c (gimple_can_coalesce_p): Allow coalescing > across base variables when optimizing. > * tree-ssa-coalesce.c (build_ssa_conflict_graph): Add > param_defaults argument. Process PARM_DECLs's default defs at > the entry point. > (attempt_coalesce): Add param_defaults argument, and > track the presence of default defs for params in each > partition. Propagate base var to leader on merge, preferring > parms and results, named vars, ignored vars, and then anon > vars. Refuse to merge a RESULT_DECL partition with a default > PARM_DECL one. > (coalesce_partitions): Add param_defaults argument, > and pass it to attempt_coalesce. > (dump_part_var_map): New. > (compute_optimized_partition_bases): New, called by... > (coalesce_ssa_name): ... when optimizing, disabling > partition_view_bitmap's base assignment. Pass local > param_defaults to coalescer functions. > * tree-ssa-live.c (var_map_base_init): Note use only when not > optimizing. > --- > gcc/Makefile.in | 1 > gcc/common.opt | 12 + > gcc/doc/invoke.texi | 29 --- > gcc/gimple-expr.c | 7 - > gcc/opts.c | 1 > gcc/passes.def | 5 > gcc/tree-ssa-coalesce.c | 342 ++++++++++++++++++++++++++++++- > gcc/tree-ssa-copyrename.c | 499 > --------------------------------------------- > gcc/tree-ssa-live.c | 5 > 9 files changed, 347 insertions(+), 554 deletions(-) > delete mode 100644 gcc/tree-ssa-copyrename.c > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > index f924fb8..990c4e9 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -1428,7 +1428,6 @@ OBJS = \ > tree-ssa-ccp.o \ > tree-ssa-coalesce.o \ > tree-ssa-copy.o \ > - tree-ssa-copyrename.o \ > tree-ssa-dce.o \ > tree-ssa-dom.o \ > tree-ssa-dse.o \ > diff --git a/gcc/common.opt b/gcc/common.opt > index b49ac46..fefaee7 100644 > --- a/gcc/common.opt > +++ b/gcc/common.opt > @@ -2207,16 +2207,16 @@ Common Report Var(flag_tree_ch) Optimization > Enable loop header copying on trees > > ftree-coalesce-inlined-vars > -Common Report Var(flag_ssa_coalesce_vars,1) Init(2) RejectNegative > Optimization > -Enable coalescing of copy-related user variables that are inlined > +Common Ignore RejectNegative > +Does nothing. Preserved for backward compatibility. > > ftree-coalesce-vars > -Common Report Var(flag_ssa_coalesce_vars,2) Optimization > -Enable coalescing of all copy-related user variables > +Common Ignore > +Does nothing. Preserved for backward compatibility. > > ftree-copyrename > -Common Report Var(flag_tree_copyrename) Optimization > -Replace SSA temporaries with better names in copies > +Common Ignore > +Does nothing. Preserved for backward compatibility. > > ftree-copy-prop > Common Report Var(flag_tree_copy_prop) Optimization > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index 9749727..5d2c516 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -442,8 +442,7 @@ Objective-C and Objective-C++ Dialects}. > -fstack-protector-explicit -fstdarg-opt -fstrict-aliasing @gol > -fstrict-overflow -fthread-jumps -ftracer -ftree-bit-ccp @gol > -ftree-builtin-call-dce -ftree-ccp -ftree-ch @gol > --ftree-coalesce-inline-vars -ftree-coalesce-vars -ftree-copy-prop @gol > --ftree-copyrename -ftree-dce -ftree-dominator-opts -ftree-dse @gol > +-ftree-copy-prop -ftree-dce -ftree-dominator-opts -ftree-dse @gol > -ftree-forwprop -ftree-fre -ftree-loop-if-convert @gol > -ftree-loop-if-convert-stores -ftree-loop-im @gol > -ftree-phiprop -ftree-loop-distribution -ftree-loop-distribute-patterns @gol > @@ -8822,32 +8821,6 @@ Perform scalar replacement of aggregates. This pass > replaces structure > references with scalars to prevent committing structures to memory too > early. This flag is enabled by default at @option{-O} and higher. > > -@item -ftree-copyrename > -@opindex ftree-copyrename > -Perform copy renaming on trees. This pass attempts to rename compiler > -temporaries to other variables at copy locations, usually resulting in > -variable names which more closely resemble the original variables. This flag > -is enabled by default at @option{-O} and higher. > - > -@item -ftree-coalesce-inlined-vars > -@opindex ftree-coalesce-inlined-vars > -Tell the copyrename pass (see @option{-ftree-copyrename}) to attempt to > -combine small user-defined variables too, but only if they are inlined > -from other functions. It is a more limited form of > -@option{-ftree-coalesce-vars}. This may harm debug information of such > -inlined variables, but it keeps variables of the inlined-into > -function apart from each other, such that they are more likely to > -contain the expected values in a debugging session. > - > -@item -ftree-coalesce-vars > -@opindex ftree-coalesce-vars > -Tell the copyrename pass (see @option{-ftree-copyrename}) to attempt to > -combine small user-defined variables too, instead of just compiler > -temporaries. This may severely limit the ability to debug an optimized > -program compiled with @option{-fno-var-tracking-assignments}. In the > -negated form, this flag prevents SSA coalescing of user variables, > -including inlined ones. This option is enabled by default. > - > @item -ftree-ter > @opindex ftree-ter > Perform temporary expression replacement during the SSA->normal phase. > Single > diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c > index efc93b7..62ae577 100644 > --- a/gcc/gimple-expr.c > +++ b/gcc/gimple-expr.c > @@ -399,13 +399,14 @@ copy_var_decl (tree var, tree name, tree type) > bool > gimple_can_coalesce_p (tree name1, tree name2) > { > - /* First check the SSA_NAME's associated DECL. We only want to > - coalesce if they have the same DECL or both have no associated DECL. */ > + /* First check the SSA_NAME's associated DECL. Without > + optimization, we only want to coalesce if they have the same DECL > + or both have no associated DECL. */ > tree var1 = SSA_NAME_VAR (name1); > tree var2 = SSA_NAME_VAR (name2); > var1 = (var1 && (!VAR_P (var1) || !DECL_IGNORED_P (var1))) ? var1 : > NULL_TREE; > var2 = (var2 && (!VAR_P (var2) || !DECL_IGNORED_P (var2))) ? var2 : > NULL_TREE; > - if (var1 != var2) > + if (var1 != var2 && !optimize) > return false; > > /* Now check the types. If the types are the same, then we should > diff --git a/gcc/opts.c b/gcc/opts.c > index 39c190d..8149421 100644 > --- a/gcc/opts.c > +++ b/gcc/opts.c > @@ -453,7 +453,6 @@ static const struct default_options > default_options_table[] = > { OPT_LEVELS_1_PLUS, OPT_ftree_dse, NULL, 1 }, > { OPT_LEVELS_1_PLUS, OPT_ftree_ter, NULL, 1 }, > { OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_ftree_sra, NULL, 1 }, > - { OPT_LEVELS_1_PLUS, OPT_ftree_copyrename, NULL, 1 }, > { OPT_LEVELS_1_PLUS, OPT_ftree_fre, NULL, 1 }, > { OPT_LEVELS_1_PLUS, OPT_ftree_copy_prop, NULL, 1 }, > { OPT_LEVELS_1_PLUS, OPT_ftree_sink, NULL, 1 }, > diff --git a/gcc/passes.def b/gcc/passes.def > index 1d598b2..f8fd0ef 100644 > --- a/gcc/passes.def > +++ b/gcc/passes.def > @@ -77,7 +77,6 @@ along with GCC; see the file COPYING3. If not see > NEXT_PASS (pass_all_early_optimizations); > PUSH_INSERT_PASSES_WITHIN (pass_all_early_optimizations) > NEXT_PASS (pass_remove_cgraph_callee_edges); > - NEXT_PASS (pass_rename_ssa_copies); > NEXT_PASS (pass_object_sizes); > NEXT_PASS (pass_ccp); > /* After CCP we rewrite no longer addressed locals into SSA > @@ -154,7 +153,6 @@ along with GCC; see the file COPYING3. If not see > /* Initial scalar cleanups before alias computation. > They ensure memory accesses are not indirect wherever possible. */ > NEXT_PASS (pass_strip_predict_hints); > - NEXT_PASS (pass_rename_ssa_copies); > NEXT_PASS (pass_ccp); > /* After CCP we rewrite no longer addressed locals into SSA > form if possible. */ > @@ -182,7 +180,6 @@ along with GCC; see the file COPYING3. If not see > NEXT_PASS (pass_stdarg); > NEXT_PASS (pass_lower_complex); > NEXT_PASS (pass_sra); > - NEXT_PASS (pass_rename_ssa_copies); > /* The dom pass will also resolve all __builtin_constant_p calls > that are still there to 0. This has to be done after some > propagations have already run, but before some more dead code > @@ -291,7 +288,6 @@ along with GCC; see the file COPYING3. If not see > NEXT_PASS (pass_fold_builtins); > NEXT_PASS (pass_optimize_widening_mul); > NEXT_PASS (pass_tail_calls); > - NEXT_PASS (pass_rename_ssa_copies); > /* FIXME: If DCE is not run before checking for uninitialized uses, > we may get false warnings (e.g., testsuite/gcc.dg/uninit-5.c). > However, this also causes us to misdiagnose cases that should be > @@ -326,7 +322,6 @@ along with GCC; see the file COPYING3. If not see > NEXT_PASS (pass_dce); > NEXT_PASS (pass_asan); > NEXT_PASS (pass_tsan); > - NEXT_PASS (pass_rename_ssa_copies); > /* ??? We do want some kind of loop invariant motion, but we possibly > need to adjust LIM to be more friendly towards preserving accurate > debug information here. */ > diff --git a/gcc/tree-ssa-coalesce.c b/gcc/tree-ssa-coalesce.c > index 1afeefe..8557d84 100644 > --- a/gcc/tree-ssa-coalesce.c > +++ b/gcc/tree-ssa-coalesce.c > @@ -825,13 +825,23 @@ live_track_clear_base_vars (live_track_p ptr) > base variable are added. */ > > static ssa_conflicts_p > -build_ssa_conflict_graph (tree_live_info_p liveinfo) > +build_ssa_conflict_graph (tree_live_info_p liveinfo, bitmap param_defaults) > { > ssa_conflicts_p graph; > var_map map; > basic_block bb; > ssa_op_iter iter; > live_track_p live; > + basic_block entry; > + > + /* If we are optimizing, we may attempt to coalesce variables from > + different base variables, including different parameters, so we > + have to make sure default defs live at the entry block conflict > + with each other. */ > + if (optimize) > + entry = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); > + else > + entry = NULL; > > map = live_var_map (liveinfo); > graph = ssa_conflicts_new (num_var_partitions (map)); > @@ -890,6 +900,36 @@ build_ssa_conflict_graph (tree_live_info_p liveinfo) > live_track_process_def (live, result, graph); > } > > + /* Pretend there are defs for params' default defs at the start > + of the (post-)entry block. We run after abnormal coalescing, > + so we can't assume the leader variable is the default > + definition, but because of SSA_NAME_VAR adjustments in > + attempt_coalesce, we can assume that if there is any > + PARM_DECL in the partition, it will be the leader's > + SSA_NAME_VAR. */ > + if (bb == entry) > + { > + unsigned base; > + bitmap_iterator bi; > + EXECUTE_IF_SET_IN_BITMAP (live->live_base_var, 0, base, bi) > + { > + bitmap_iterator bi2; > + unsigned part; > + EXECUTE_IF_SET_IN_BITMAP (live->live_base_partitions[base], > + 0, part, bi2) > + { > + tree var = partition_to_var (map, part); > + if (!SSA_NAME_VAR (var) > + || TREE_CODE (SSA_NAME_VAR (var)) != PARM_DECL > + || !(SSA_NAME_IS_DEFAULT_DEF (var) > + || (param_defaults > + && bitmap_bit_p (param_defaults, part)))) > + continue; > + live_track_process_def (live, var, graph); > + } > + } > + } > + This looks somewhat awkward to me ;) Is it really important to allow coalescing PARM_DECL-based SSA vars with sth else? At least abnormal coalescing doesn't need to do that, so just walking over the function decls parameters and making their default-def live should be enough? That is, that param_defaults bitmap looks ugly to me. > live_track_clear_base_vars (live); > } > > @@ -1126,11 +1166,12 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap > used_in_copy) > > static inline bool > attempt_coalesce (var_map map, ssa_conflicts_p graph, int x, int y, > - FILE *debug) > + bitmap param_defaults, FILE *debug) > { > int z; > tree var1, var2; > int p1, p2; > + bool default_def = false; > > p1 = var_to_partition (map, ssa_name (x)); > p2 = var_to_partition (map, ssa_name (y)); > @@ -1158,6 +1199,70 @@ attempt_coalesce (var_map map, ssa_conflicts_p graph, > int x, int y, > { > var1 = partition_to_var (map, p1); > var2 = partition_to_var (map, p2); > + > + tree leader; > + > + if (var1 == var2 || !SSA_NAME_VAR (var2) > + || SSA_NAME_VAR (var1) == SSA_NAME_VAR (var2)) > + { > + leader = SSA_NAME_VAR (var1); > + default_def = (leader && TREE_CODE (leader) == PARM_DECL > + && (SSA_NAME_IS_DEFAULT_DEF (var1) > + || bitmap_bit_p (param_defaults, p1))); > + } > + else if (!SSA_NAME_VAR (var1)) > + { > + leader = SSA_NAME_VAR (var2); > + default_def = (leader && TREE_CODE (leader) == PARM_DECL > + && (SSA_NAME_IS_DEFAULT_DEF (var2) > + || bitmap_bit_p (param_defaults, p2))); > + } > + else if ((TREE_CODE (SSA_NAME_VAR (var1)) == PARM_DECL > + && (SSA_NAME_IS_DEFAULT_DEF (var1) > + || bitmap_bit_p (param_defaults, p1))) > + || TREE_CODE (SSA_NAME_VAR (var1)) == RESULT_DECL) > + { > + if ((TREE_CODE (SSA_NAME_VAR (var2)) == PARM_DECL > + && (SSA_NAME_IS_DEFAULT_DEF (var2) > + || bitmap_bit_p (param_defaults, p2))) > + || TREE_CODE (SSA_NAME_VAR (var2)) == RESULT_DECL) > + { > + /* We only have one RESULT_DECL, and two PARM_DECL > + DEFAULT_DEFs would have conflicted, so we know either > + one of var1 or var2 is a PARM_DECL, and the other is > + a RESULT_DECL. */ > + if (debug) > + fprintf (debug, ": Cannot coalesce PARM_DECL and > RESULT_DECL\n"); > + return false; > + } > + leader = SSA_NAME_VAR (var1); > + default_def = TREE_CODE (leader) == PARM_DECL; > + } > + else if ((TREE_CODE (SSA_NAME_VAR (var2)) == PARM_DECL > + && (SSA_NAME_IS_DEFAULT_DEF (var2) > + || bitmap_bit_p (param_defaults, p2))) > + || TREE_CODE (SSA_NAME_VAR (var2)) == RESULT_DECL) > + { > + leader = SSA_NAME_VAR (var2); > + default_def = TREE_CODE (leader) == PARM_DECL; > + } > + else if (TREE_CODE (SSA_NAME_VAR (var1)) == PARM_DECL) > + leader = SSA_NAME_VAR (var1); > + else if (TREE_CODE (SSA_NAME_VAR (var2)) == PARM_DECL) > + leader = SSA_NAME_VAR (var2); > + else if (TREE_CODE (SSA_NAME_VAR (var1)) == VAR_DECL > + && !DECL_IGNORED_P (SSA_NAME_VAR (var1))) > + leader = SSA_NAME_VAR (var1); > + else if (TREE_CODE (SSA_NAME_VAR (var2)) == VAR_DECL > + && !DECL_IGNORED_P (SSA_NAME_VAR (var2))) > + leader = SSA_NAME_VAR (var2); > + else if (TREE_CODE (SSA_NAME_VAR (var1)) == VAR_DECL) > + leader = SSA_NAME_VAR (var1); > + else if (TREE_CODE (SSA_NAME_VAR (var2)) == VAR_DECL) > + leader = SSA_NAME_VAR (var2); > + else /* What else could it be? */ > + gcc_unreachable (); > + definitely comments missing in this spaghetti... > z = var_union (map, var1, var2); > if (z == NO_PARTITION) > { > @@ -1173,8 +1278,46 @@ attempt_coalesce (var_map map, ssa_conflicts_p graph, > int x, int y, > else > ssa_conflicts_merge (graph, p2, p1); > > + if (z == p1) > + { > + if (SSA_NAME_VAR (var1) != leader) > + { > + replace_ssa_name_symbol (var1, leader); > + if (debug) > + { > + fprintf (debug, ": Renamed "); > + print_generic_expr (debug, var1, TDF_SLIM); > + } > + } > + if (default_def) > + { > + if (SSA_NAME_IS_DEFAULT_DEF (var2)) > + bitmap_clear_bit (param_defaults, p2); > + bitmap_set_bit (param_defaults, p1); > + } > + } > + else > + { > + if (SSA_NAME_VAR (var2) != leader) > + { > + replace_ssa_name_symbol (var2, leader); > + if (debug) > + { > + fprintf (debug, ": Renamed "); > + print_generic_expr (debug, var2, TDF_SLIM); > + } > + } > + if (default_def) > + { > + if (SSA_NAME_IS_DEFAULT_DEF (var1)) > + bitmap_clear_bit (param_defaults, p1); > + bitmap_set_bit (param_defaults, p2); > + } > + } or seeing this, why coalesce default-defs at all? Either they are param values or they have indetermined values (and thus we can and do pick whatever is available at expansion time)? > + > if (debug) > fprintf (debug, ": Success -> %d\n", z); > + > return true; > } > > @@ -1190,7 +1333,7 @@ attempt_coalesce (var_map map, ssa_conflicts_p graph, > int x, int y, > > static void > coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl, > - FILE *debug) > + bitmap param_defaults, FILE *debug) > { > int x = 0, y = 0; > tree var1, var2; > @@ -1226,7 +1369,7 @@ coalesce_partitions (var_map map, ssa_conflicts_p > graph, coalesce_list_p cl, > if (debug) > fprintf (debug, "Abnormal coalesce: "); > > - if (!attempt_coalesce (map, graph, v1, v2, debug)) > + if (!attempt_coalesce (map, graph, v1, v2, param_defaults, > debug)) > fail_abnormal_edge_coalesce (v1, v2); > } > } > @@ -1244,7 +1387,7 @@ coalesce_partitions (var_map map, ssa_conflicts_p > graph, coalesce_list_p cl, > > if (debug) > fprintf (debug, "Coalesce list: "); > - attempt_coalesce (map, graph, x, y, debug); > + attempt_coalesce (map, graph, x, y, param_defaults, debug); > } > } > > @@ -1272,6 +1415,178 @@ ssa_name_var_hash::equal (const value_type *n1, const > compare_type *n2) > } > > > +/* Output partition map MAP with coalescing plan PART to file F. */ > + > +void > +dump_part_var_map (FILE *f, partition part, var_map map) > +{ > + int t; > + unsigned x, y; > + int p; > + > + fprintf (f, "\nCoalescible Partition map \n\n"); > + > + for (x = 0; x < map->num_partitions; x++) > + { > + if (map->view_to_partition != NULL) > + p = map->view_to_partition[x]; > + else > + p = x; > + > + if (ssa_name (p) == NULL_TREE > + || virtual_operand_p (ssa_name (p))) > + continue; > + > + t = 0; > + for (y = 1; y < num_ssa_names; y++) > + { > + tree var = version_to_var (map, y); > + if (!var) > + continue; > + int q = var_to_partition (map, var); > + p = partition_find (part, q); > + gcc_assert (map->partition_to_base_index[q] > + == map->partition_to_base_index[p]); > + > + if (p == (int)x) > + { > + if (t++ == 0) > + { > + fprintf (f, "Partition %d, base %d (", x, > + map->partition_to_base_index[q]); > + print_generic_expr (f, partition_to_var (map, q), TDF_SLIM); > + fprintf (f, " - "); > + } > + fprintf (f, "%d ", y); > + } > + } > + if (t != 0) > + fprintf (f, ")\n"); > + } > + fprintf (f, "\n"); > +} > + > +/* Fill in MAP's partition_to_base_index, with one index for each > + partition of SSA names USED_IN_COPIES and related by CL > + coalesce possibilities. */ > + > +static void > +compute_optimized_partition_bases (var_map map, bitmap used_in_copies, > + coalesce_list_p cl) > +{ > + int parts = num_var_partitions (map); > + partition tentative = partition_new (parts); > + > + /* Partition the SSA versions so that, for each coalescible > + pair, both of its members are in the same partition in > + TENTATIVE. */ > + gcc_assert (!cl->sorted); > + coalesce_pair_p node; > + coalesce_iterator_type ppi; > + FOR_EACH_PARTITION_PAIR (node, ppi, cl) > + { > + tree v1 = ssa_name (node->first_element); > + int p1 = partition_find (tentative, var_to_partition (map, v1)); > + tree v2 = ssa_name (node->second_element); > + int p2 = partition_find (tentative, var_to_partition (map, v2)); > + > + if (p1 == p2) > + continue; > + > + partition_union (tentative, p1, p2); > + } > + > + /* We have to deal with cost one pairs too. */ > + for (cost_one_pair_d *co = cl->cost_one_list; co; co = co->next) > + { > + tree v1 = ssa_name (co->first_element); > + int p1 = partition_find (tentative, var_to_partition (map, v1)); > + tree v2 = ssa_name (co->second_element); > + int p2 = partition_find (tentative, var_to_partition (map, v2)); > + > + if (p1 == p2) > + continue; > + > + partition_union (tentative, p1, p2); > + } > + > + /* And also with abnormal edges. */ > + basic_block bb; > + edge e; > + edge_iterator ei; > + FOR_EACH_BB_FN (bb, cfun) > + { > + 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 p1 = partition_find (tentative, var_to_partition (map, > res)); > + int p2 = partition_find (tentative, var_to_partition (map, > arg)); > + > + if (p1 == p2) > + continue; > + > + partition_union (tentative, p1, p2); > + } > + } > + } So the above does full coalescing ignoring conflicts. > + > + map->partition_to_base_index = XCNEWVEC (int, parts); > + auto_vec<unsigned int> index_map (parts); > + if (parts) > + index_map.quick_grow (parts); > + > + const unsigned no_part = -1; > + unsigned count = parts; > + while (count) > + index_map[--count] = no_part; > + > + /* Initialize MAP's mapping from partition to base index, using > + as base indices an enumeration of the TENTATIVE partitions in > + which each SSA version ended up, so that we compute conflicts > + between all SSA versions that ended up in the same potential > + coalesce partition. */ > + bitmap_iterator bi; > + unsigned i; > + EXECUTE_IF_SET_IN_BITMAP (used_in_copies, 0, i, bi) > + { > + int pidx = var_to_partition (map, ssa_name (i)); > + int base = partition_find (tentative, pidx); > + if (index_map[base] != no_part) > + continue; > + index_map[base] = count++; > + } > + > + map->num_basevars = count; Did you do any statistics on how the number of basevars changes with your patch compared to trunk? So apart from possibly simplifying the patch by not dealing with default-def coalesces of PARAM_DECLs and ignoring them for conflict purposes for others (as tree-ssa-live.c does) the patch looks good to me. Richard. > + EXECUTE_IF_SET_IN_BITMAP (used_in_copies, 0, i, bi) > + { > + int pidx = var_to_partition (map, ssa_name (i)); > + int base = partition_find (tentative, pidx); > + gcc_assert (index_map[base] < count); > + map->partition_to_base_index[pidx] = index_map[base]; > + } > + > + if (dump_file && (dump_flags & TDF_DETAILS)) > + dump_part_var_map (dump_file, tentative, map); > + > + partition_delete (tentative); > +} > + > + > /* Reduce the number of copies by coalescing variables in the function. > Return > a partition map with the resulting coalesces. */ > > @@ -1332,7 +1647,12 @@ coalesce_ssa_name (void) > dump_var_map (dump_file, map); > > /* Don't calculate live ranges for variables not in the coalesce list. */ > - partition_view_bitmap (map, used_in_copies, true); > + partition_view_bitmap (map, used_in_copies, !optimize); > + > + /* If we are optimizing, compute the base indices ourselves. */ > + if (optimize) > + compute_optimized_partition_bases (map, used_in_copies, cl); > + > BITMAP_FREE (used_in_copies); > > if (num_var_partitions (map) < 1) > @@ -1341,6 +1661,8 @@ coalesce_ssa_name (void) > return map; > } > > + bitmap param_defaults = BITMAP_ALLOC (NULL); > + > if (dump_file && (dump_flags & TDF_DETAILS)) > dump_var_map (dump_file, map); > > @@ -1350,7 +1672,7 @@ coalesce_ssa_name (void) > dump_live_info (dump_file, liveinfo, LIVEDUMP_ENTRY); > > /* Build a conflict graph. */ > - graph = build_ssa_conflict_graph (liveinfo); > + graph = build_ssa_conflict_graph (liveinfo, param_defaults); > delete_tree_live_info (liveinfo); > if (dump_file && (dump_flags & TDF_DETAILS)) > ssa_conflicts_dump (dump_file, graph); > @@ -1370,10 +1692,10 @@ coalesce_ssa_name (void) > dump_var_map (dump_file, map); > > /* Now coalesce everything in the list. */ > - coalesce_partitions (map, graph, cl, > - ((dump_flags & TDF_DETAILS) ? dump_file > - : NULL)); > + coalesce_partitions (map, graph, cl, param_defaults, > + ((dump_flags & TDF_DETAILS) ? dump_file : NULL)); > > + BITMAP_FREE (param_defaults); > delete_coalesce_list (cl); > ssa_conflicts_delete (graph); > > diff --git a/gcc/tree-ssa-copyrename.c b/gcc/tree-ssa-copyrename.c > deleted file mode 100644 > index f3cb56e..0000000 > --- a/gcc/tree-ssa-copyrename.c > +++ /dev/null > @@ -1,499 +0,0 @@ > -/* Rename SSA copies. > - Copyright (C) 2004-2015 Free Software Foundation, Inc. > - Contributed by Andrew MacLeod <amacl...@redhat.com> > - > -This file is part of GCC. > - > -GCC is free software; you can redistribute it and/or modify > -it under the terms of the GNU General Public License as published by > -the Free Software Foundation; either version 3, or (at your option) > -any later version. > - > -GCC is distributed in the hope that it will be useful, > -but WITHOUT ANY WARRANTY; without even the implied warranty of > -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > -GNU General Public License for more details. > - > -You should have received a copy of the GNU General Public License > -along with GCC; see the file COPYING3. If not see > -<http://www.gnu.org/licenses/>. */ > - > -#include "config.h" > -#include "system.h" > -#include "coretypes.h" > -#include "tm.h" > -#include "hash-set.h" > -#include "machmode.h" > -#include "vec.h" > -#include "double-int.h" > -#include "input.h" > -#include "alias.h" > -#include "symtab.h" > -#include "wide-int.h" > -#include "inchash.h" > -#include "tree.h" > -#include "fold-const.h" > -#include "predict.h" > -#include "hard-reg-set.h" > -#include "function.h" > -#include "dominance.h" > -#include "cfg.h" > -#include "basic-block.h" > -#include "tree-ssa-alias.h" > -#include "internal-fn.h" > -#include "gimple-expr.h" > -#include "is-a.h" > -#include "gimple.h" > -#include "gimple-iterator.h" > -#include "flags.h" > -#include "tree-pretty-print.h" > -#include "bitmap.h" > -#include "gimple-ssa.h" > -#include "stringpool.h" > -#include "tree-ssanames.h" > -#include "hashtab.h" > -#include "rtl.h" > -#include "statistics.h" > -#include "real.h" > -#include "fixed-value.h" > -#include "insn-config.h" > -#include "expmed.h" > -#include "dojump.h" > -#include "explow.h" > -#include "calls.h" > -#include "emit-rtl.h" > -#include "varasm.h" > -#include "stmt.h" > -#include "expr.h" > -#include "tree-dfa.h" > -#include "tree-inline.h" > -#include "tree-ssa-live.h" > -#include "tree-pass.h" > -#include "langhooks.h" > - > -static struct > -{ > - /* Number of copies coalesced. */ > - int coalesced; > -} stats; > - > -/* The following routines implement the SSA copy renaming phase. > - > - This optimization looks for copies between 2 SSA_NAMES, either through a > - direct copy, or an implicit one via a PHI node result and its arguments. > - > - Each copy is examined to determine if it is possible to rename the base > - variable of one of the operands to the same variable as the other operand. > - i.e. > - T.3_5 = <blah> > - a_1 = T.3_5 > - > - If this copy couldn't be copy propagated, it could possibly remain in the > - program throughout the optimization phases. After SSA->normal, it would > - become: > - > - T.3 = <blah> > - a = T.3 > - > - Since T.3_5 is distinct from all other SSA versions of T.3, there is no > - fundamental reason why the base variable needs to be T.3, subject to > - certain restrictions. This optimization attempts to determine if we can > - change the base variable on copies like this, and result in code such as: > - > - a_5 = <blah> > - a_1 = a_5 > - > - This gives the SSA->normal pass a shot at coalescing a_1 and a_5. If it is > - possible, the copy goes away completely. If it isn't possible, a new temp > - will be created for a_5, and you will end up with the exact same code: > - > - a.8 = <blah> > - a = a.8 > - > - The other benefit of performing this optimization relates to what > variables > - are chosen in copies. Gimplification of the program uses temporaries for > - a lot of things. expressions like > - > - a_1 = <blah> > - <blah2> = a_1 > - > - get turned into > - > - T.3_5 = <blah> > - a_1 = T.3_5 > - <blah2> = a_1 > - > - Copy propagation is done in a forward direction, and if we can propagate > - through the copy, we end up with: > - > - T.3_5 = <blah> > - <blah2> = T.3_5 > - > - The copy is gone, but so is all reference to the user variable 'a'. By > - performing this optimization, we would see the sequence: > - > - a_5 = <blah> > - a_1 = a_5 > - <blah2> = a_1 > - > - which copy propagation would then turn into: > - > - a_5 = <blah> > - <blah2> = a_5 > - > - and so we still retain the user variable whenever possible. */ > - > - > -/* Coalesce the partitions in MAP representing VAR1 and VAR2 if it is valid. > - Choose a representative for the partition, and send debug info to DEBUG. > */ > - > -static void > -copy_rename_partition_coalesce (var_map map, tree var1, tree var2, FILE > *debug) > -{ > - int p1, p2, p3; > - tree root1, root2; > - tree rep1, rep2; > - bool ign1, ign2, abnorm; > - > - gcc_assert (TREE_CODE (var1) == SSA_NAME); > - gcc_assert (TREE_CODE (var2) == SSA_NAME); > - > - register_ssa_partition (map, var1); > - register_ssa_partition (map, var2); > - > - p1 = partition_find (map->var_partition, SSA_NAME_VERSION (var1)); > - p2 = partition_find (map->var_partition, SSA_NAME_VERSION (var2)); > - > - if (debug) > - { > - fprintf (debug, "Try : "); > - print_generic_expr (debug, var1, TDF_SLIM); > - fprintf (debug, "(P%d) & ", p1); > - print_generic_expr (debug, var2, TDF_SLIM); > - fprintf (debug, "(P%d)", p2); > - } > - > - gcc_assert (p1 != NO_PARTITION); > - gcc_assert (p2 != NO_PARTITION); > - > - if (p1 == p2) > - { > - if (debug) > - fprintf (debug, " : Already coalesced.\n"); > - return; > - } > - > - rep1 = partition_to_var (map, p1); > - rep2 = partition_to_var (map, p2); > - root1 = SSA_NAME_VAR (rep1); > - root2 = SSA_NAME_VAR (rep2); > - if (!root1 && !root2) > - return; > - > - /* Don't coalesce if one of the variables occurs in an abnormal PHI. */ > - abnorm = (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rep1) > - || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rep2)); > - if (abnorm) > - { > - if (debug) > - fprintf (debug, " : Abnormal PHI barrier. No coalesce.\n"); > - return; > - } > - > - /* Partitions already have the same root, simply merge them. */ > - if (root1 == root2) > - { > - p1 = partition_union (map->var_partition, p1, p2); > - if (debug) > - fprintf (debug, " : Same root, coalesced --> P%d.\n", p1); > - return; > - } > - > - /* Never attempt to coalesce 2 different parameters. */ > - if ((root1 && TREE_CODE (root1) == PARM_DECL) > - && (root2 && TREE_CODE (root2) == PARM_DECL)) > - { > - if (debug) > - fprintf (debug, " : 2 different PARM_DECLS. No coalesce.\n"); > - return; > - } > - > - if ((root1 && TREE_CODE (root1) == RESULT_DECL) > - != (root2 && TREE_CODE (root2) == RESULT_DECL)) > - { > - if (debug) > - fprintf (debug, " : One root a RESULT_DECL. No coalesce.\n"); > - return; > - } > - > - ign1 = !root1 || (TREE_CODE (root1) == VAR_DECL && DECL_IGNORED_P (root1)); > - ign2 = !root2 || (TREE_CODE (root2) == VAR_DECL && DECL_IGNORED_P (root2)); > - > - /* Refrain from coalescing user variables, if requested. */ > - if (!ign1 && !ign2) > - { > - if (flag_ssa_coalesce_vars && DECL_FROM_INLINE (root2)) > - ign2 = true; > - else if (flag_ssa_coalesce_vars && DECL_FROM_INLINE (root1)) > - ign1 = true; > - else if (flag_ssa_coalesce_vars != 2) > - { > - if (debug) > - fprintf (debug, " : 2 different USER vars. No coalesce.\n"); > - return; > - } > - else > - ign2 = true; > - } > - > - /* If both values have default defs, we can't coalesce. If only one has a > - tag, make sure that variable is the new root partition. */ > - if (root1 && ssa_default_def (cfun, root1)) > - { > - if (root2 && ssa_default_def (cfun, root2)) > - { > - if (debug) > - fprintf (debug, " : 2 default defs. No coalesce.\n"); > - return; > - } > - else > - { > - ign2 = true; > - ign1 = false; > - } > - } > - else if (root2 && ssa_default_def (cfun, root2)) > - { > - ign1 = true; > - ign2 = false; > - } > - > - /* Do not coalesce if we cannot assign a symbol to the partition. */ > - if (!(!ign2 && root2) > - && !(!ign1 && root1)) > - { > - if (debug) > - fprintf (debug, " : Choosen variable has no root. No coalesce.\n"); > - return; > - } > - > - /* Don't coalesce if the new chosen root variable would be read-only. > - If both ign1 && ign2, then the root var of the larger partition > - wins, so reject in that case if any of the root vars is TREE_READONLY. > - Otherwise reject only if the root var, on which replace_ssa_name_symbol > - will be called below, is readonly. */ > - if (((root1 && TREE_READONLY (root1)) && ign2) > - || ((root2 && TREE_READONLY (root2)) && ign1)) > - { > - if (debug) > - fprintf (debug, " : Readonly variable. No coalesce.\n"); > - return; > - } > - > - /* Don't coalesce if the two variables aren't type compatible . */ > - if (!types_compatible_p (TREE_TYPE (var1), TREE_TYPE (var2)) > - /* There is a disconnect between the middle-end type-system and > - VRP, avoid coalescing enum types with different bounds. */ > - || ((TREE_CODE (TREE_TYPE (var1)) == ENUMERAL_TYPE > - || TREE_CODE (TREE_TYPE (var2)) == ENUMERAL_TYPE) > - && TREE_TYPE (var1) != TREE_TYPE (var2))) > - { > - if (debug) > - fprintf (debug, " : Incompatible types. No coalesce.\n"); > - return; > - } > - > - /* Merge the two partitions. */ > - p3 = partition_union (map->var_partition, p1, p2); > - > - /* Set the root variable of the partition to the better choice, if there is > - one. */ > - if (!ign2 && root2) > - replace_ssa_name_symbol (partition_to_var (map, p3), root2); > - else if (!ign1 && root1) > - replace_ssa_name_symbol (partition_to_var (map, p3), root1); > - else > - gcc_unreachable (); > - > - if (debug) > - { > - fprintf (debug, " --> P%d ", p3); > - print_generic_expr (debug, SSA_NAME_VAR (partition_to_var (map, p3)), > - TDF_SLIM); > - fprintf (debug, "\n"); > - } > -} > - > - > -namespace { > - > -const pass_data pass_data_rename_ssa_copies = > -{ > - GIMPLE_PASS, /* type */ > - "copyrename", /* name */ > - OPTGROUP_NONE, /* optinfo_flags */ > - TV_TREE_COPY_RENAME, /* tv_id */ > - ( PROP_cfg | PROP_ssa ), /* properties_required */ > - 0, /* properties_provided */ > - 0, /* properties_destroyed */ > - 0, /* todo_flags_start */ > - 0, /* todo_flags_finish */ > -}; > - > -class pass_rename_ssa_copies : public gimple_opt_pass > -{ > -public: > - pass_rename_ssa_copies (gcc::context *ctxt) > - : gimple_opt_pass (pass_data_rename_ssa_copies, ctxt) > - {} > - > - /* opt_pass methods: */ > - opt_pass * clone () { return new pass_rename_ssa_copies (m_ctxt); } > - virtual bool gate (function *) { return flag_tree_copyrename != 0; } > - virtual unsigned int execute (function *); > - > -}; // class pass_rename_ssa_copies > - > -/* This function will make a pass through the IL, and attempt to coalesce any > - SSA versions which occur in PHI's or copies. Coalescing is accomplished > by > - changing the underlying root variable of all coalesced version. This will > - then cause the SSA->normal pass to attempt to coalesce them all to the > same > - variable. */ > - > -unsigned int > -pass_rename_ssa_copies::execute (function *fun) > -{ > - var_map map; > - basic_block bb; > - tree var, part_var; > - gimple stmt; > - unsigned x; > - FILE *debug; > - > - memset (&stats, 0, sizeof (stats)); > - > - if (dump_file && (dump_flags & TDF_DETAILS)) > - debug = dump_file; > - else > - debug = NULL; > - > - map = init_var_map (num_ssa_names); > - > - FOR_EACH_BB_FN (bb, fun) > - { > - /* Scan for real copies. */ > - for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); > - gsi_next (&gsi)) > - { > - stmt = gsi_stmt (gsi); > - if (gimple_assign_ssa_name_copy_p (stmt)) > - { > - tree lhs = gimple_assign_lhs (stmt); > - tree rhs = gimple_assign_rhs1 (stmt); > - > - copy_rename_partition_coalesce (map, lhs, rhs, debug); > - } > - } > - } > - > - FOR_EACH_BB_FN (bb, fun) > - { > - /* Treat PHI nodes as copies between the result and each argument. */ > - for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi); > - gsi_next (&gsi)) > - { > - size_t i; > - tree res; > - gphi *phi = gsi.phi (); > - res = gimple_phi_result (phi); > - > - /* Do not process virtual SSA_NAMES. */ > - if (virtual_operand_p (res)) > - continue; > - > - /* Make sure to only use the same partition for an argument > - as the result but never the other way around. */ > - if (SSA_NAME_VAR (res) > - && !DECL_IGNORED_P (SSA_NAME_VAR (res))) > - for (i = 0; i < gimple_phi_num_args (phi); i++) > - { > - tree arg = PHI_ARG_DEF (phi, i); > - if (TREE_CODE (arg) == SSA_NAME) > - copy_rename_partition_coalesce (map, res, arg, > - debug); > - } > - /* Else if all arguments are in the same partition try to merge > - it with the result. */ > - else > - { > - int all_p_same = -1; > - int p = -1; > - for (i = 0; i < gimple_phi_num_args (phi); i++) > - { > - tree arg = PHI_ARG_DEF (phi, i); > - if (TREE_CODE (arg) != SSA_NAME) > - { > - all_p_same = 0; > - break; > - } > - else if (all_p_same == -1) > - { > - p = partition_find (map->var_partition, > - SSA_NAME_VERSION (arg)); > - all_p_same = 1; > - } > - else if (all_p_same == 1 > - && p != partition_find (map->var_partition, > - SSA_NAME_VERSION (arg))) > - { > - all_p_same = 0; > - break; > - } > - } > - if (all_p_same == 1) > - copy_rename_partition_coalesce (map, res, > - PHI_ARG_DEF (phi, 0), > - debug); > - } > - } > - } > - > - if (debug) > - dump_var_map (debug, map); > - > - /* Now one more pass to make all elements of a partition share the same > - root variable. */ > - > - for (x = 1; x < num_ssa_names; x++) > - { > - part_var = partition_to_var (map, x); > - if (!part_var) > - continue; > - var = ssa_name (x); > - if (SSA_NAME_VAR (var) == SSA_NAME_VAR (part_var)) > - continue; > - if (debug) > - { > - fprintf (debug, "Coalesced "); > - print_generic_expr (debug, var, TDF_SLIM); > - fprintf (debug, " to "); > - print_generic_expr (debug, part_var, TDF_SLIM); > - fprintf (debug, "\n"); > - } > - stats.coalesced++; > - replace_ssa_name_symbol (var, SSA_NAME_VAR (part_var)); > - } > - > - statistics_counter_event (fun, "copies coalesced", > - stats.coalesced); > - delete_var_map (map); > - return 0; > -} > - > -} // anon namespace > - > -gimple_opt_pass * > -make_pass_rename_ssa_copies (gcc::context *ctxt) > -{ > - return new pass_rename_ssa_copies (ctxt); > -} > diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c > index e0c42669..46b1869 100644 > --- a/gcc/tree-ssa-live.c > +++ b/gcc/tree-ssa-live.c > @@ -119,7 +119,10 @@ tree_int_map_hasher::equal (const value_type *v, const > compare_type *c) > } > > > -/* This routine will initialize the basevar fields of MAP. */ > +/* This routine will initialize the basevar fields of MAP with base > + names, when we are not optimizing. When optimizing, we'll use > + partition numbers as base index numbers, see coalesce_ssa_name in > + tree-ssa-coalesce.c. */ > > static void > var_map_base_init (var_map map) > > > -- > Alexandre Oliva, freedom fighter http://FSFLA.org/~lxoliva/ > You must be the change you wish to see in the world. -- Gandhi > Be Free! -- http://FSFLA.org/ FSF Latin America board member > Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer