This fixes PR59715 by splitting critical edges again before code sinking. The critical edge splitting done before PRE was designed to survive until sinking originally, but at least since 4.5 PRE now eventually cleans up the CFG and thus undos critical edge splitting. This results in less than optimal code placement (and lost opportunities) for sinking and it breaks (at least) the virtual operand updating code which assumes that critical edges are still split.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied. Richard. 2014-01-09 Richard Biener <rguent...@suse.de> PR tree-optimization/59715 * tree-cfg.h (split_critical_edges): Declare. * tree-cfg.c (split_critical_edges): Export. * tree-ssa-sink.c (execute_sink_code): Split critical edges. * gcc.dg/torture/pr59715.c: New testcase. Index: gcc/tree-cfg.h =================================================================== *** gcc/tree-cfg.h (revision 206421) --- gcc/tree-cfg.h (working copy) *************** extern tree gimplify_build1 (gimple_stmt *** 93,97 **** --- 93,98 ---- tree, tree); extern void extract_true_false_edges_from_block (basic_block, edge *, edge *); extern unsigned int execute_fixup_cfg (void); + extern unsigned int split_critical_edges (void); #endif /* _TREE_CFG_H */ Index: gcc/tree-cfg.c =================================================================== *** gcc/tree-cfg.c (revision 206421) --- gcc/tree-cfg.c (working copy) *************** static void make_goto_expr_edges (basic_ *** 159,165 **** static void make_gimple_asm_edges (basic_block); static edge gimple_redirect_edge_and_branch (edge, basic_block); static edge gimple_try_redirect_by_replacing_jump (edge, basic_block); - static unsigned int split_critical_edges (void); /* Various helpers. */ static inline bool stmt_starts_bb_p (gimple, gimple); --- 159,164 ---- *************** struct cfg_hooks gimple_cfg_hooks = { *** 7929,7935 **** /* Split all critical edges. */ ! static unsigned int split_critical_edges (void) { basic_block bb; --- 7954,7960 ---- /* Split all critical edges. */ ! unsigned int split_critical_edges (void) { basic_block bb; Index: gcc/tree-ssa-sink.c =================================================================== *** gcc/tree-ssa-sink.c (revision 206421) --- gcc/tree-ssa-sink.c (working copy) *************** static void *** 567,573 **** execute_sink_code (void) { loop_optimizer_init (LOOPS_NORMAL); ! connect_infinite_loops_to_exit (); memset (&sink_stats, 0, sizeof (sink_stats)); calculate_dominance_info (CDI_DOMINATORS); --- 567,573 ---- execute_sink_code (void) { loop_optimizer_init (LOOPS_NORMAL); ! split_critical_edges (); connect_infinite_loops_to_exit (); memset (&sink_stats, 0, sizeof (sink_stats)); calculate_dominance_info (CDI_DOMINATORS); Index: gcc/testsuite/gcc.dg/torture/pr59715.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr59715.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr59715.c (working copy) *************** *** 0 **** --- 1,21 ---- + /* { dg-do run } */ + + extern void abort (void); + + int a = 2, b; + + int + main () + { + int c; + if (!b) + { + b = a; + c = a == 0 ? 1 : 1 % a; + if (c) + b = 0; + } + if (b != 0) + abort (); + return 0; + }