Hello, As-is, tree-ssa-sink.c can only sink GIMPLE_ASSIGN statements. This patch lets tree-ssa-sink.c sink pure calls also.
This allows the pass to sink the call to use in the following test case (new test case, ssa-sink-10.c to be): ---------------------- 8< ---------------- /* { dg-do compile } */ /* { dg-options "-O -fdump-tree-sink" } */ __attribute__((__noinline__,__noclone__,__pure__,__const__)) int use (int b) { return b * 2 + 4; } int foo (int b, int c, int d) { int res, r = 0; res = use (b); if (c) r = res; return r; } /* use(b) should be sunk below the if(c). */ /* { dg-final { scan-tree-dump-times "Sinking.*use" 1 "sink" } } */ /* { dg-final { cleanup-tree-dump "sink" } } */ ---------------------- 8< ---------------- so that the optimized code (.092t.sink dump) looks like this: ;; Function foo (foo, funcdef_no=1, decl_uid=2008, cgraph_uid=1) ... Sinking r_3 = use (b_2(D)); from bb 2 to bb 3 foo (int b, int c, int d) { int r; <bb 2>: if (c_4(D) != 0) goto <bb 3>; else goto <bb 5>; <bb 5>: goto <bb 4>; <bb 3>: r_3 = use (b_2(D)); <bb 4>: # r_1 = PHI <0(5), r_3(3)> return r_1; } The patch allows the sinking of a number of functions in GCC itself (mostly simple predicates e.g. from gimple.h) to be sunk in an LTO bootstrap. The patch is a bit larger than necessary because I cleaned up the comments a bit. The only real changes are these three bits: /* We only can sink assignments. */ - if (!is_gimple_assign (stmt)) + stmt_lhs = gimple_get_lhs (stmt); + if (stmt_lhs == NULL_TREE) return false; and - && TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt))) == BLKmode)) + && TYPE_MODE (TREE_TYPE (stmt_lhs)) == BLKmode)) and - && operand_equal_p (gimple_assign_lhs (stmt), - gimple_assign_lhs (use_stmt), 0)) + && operand_equal_p (stmt_lhs, gimple_assign_lhs (use_stmt), 0)) continue; Bootstrapped&tested on powerpc64-unknown-linux-gnu. OK for GCC 4.9 stage1? Ciao! Steven gcc/ * tree-ssa-sink.c (statement_sink_location): Handle pure calls. testsuite/ * gcc.dg/tree-ssa/ssa-sink-10.c: New test. Index: tree-ssa-sink.c =================================================================== --- tree-ssa-sink.c (revision 194924) +++ tree-ssa-sink.c (working copy) @@ -264,56 +264,48 @@ statement_sink_location (gimple stmt, basic_block def_operand_p def_p; ssa_op_iter iter; imm_use_iterator imm_iter; + tree stmt_lhs; /* We only can sink assignments. */ - if (!is_gimple_assign (stmt)) + stmt_lhs = gimple_get_lhs (stmt); + if (stmt_lhs == NULL_TREE) return false; - /* We only can sink stmts with a single definition. */ + /* We only can sink stmts with a single definition. + We don't want to sink dead code, so anything with 0 immediate uses + is not sunk. */ def_p = single_ssa_def_operand (stmt, SSA_OP_ALL_DEFS); - if (def_p == NULL_DEF_OPERAND_P) + if (def_p == NULL_DEF_OPERAND_P + || has_zero_uses (DEF_FROM_PTR (def_p))) return false; - /* Return if there are no immediate uses of this stmt. */ - if (has_zero_uses (DEF_FROM_PTR (def_p))) - return false; - /* There are a few classes of things we can't or don't move, some because we don't have code to handle it, some because it's not profitable and some - because it's not legal. + because it's not legal. */ - We can't sink things that may be global stores, at least not without - calculating a lot more information, because we may cause it to no longer - be seen by an external routine that needs it depending on where it gets - moved to. - - We don't want to sink loads from memory. - - We can't sink statements that end basic blocks without splitting the - incoming edge for the sink location to place it there. - - We can't sink statements that have volatile operands. - - We don't want to sink dead code, so anything with 0 immediate uses is not - sunk. - - Don't sink BLKmode assignments if current function has any local explicit - register variables, as BLKmode assignments may involve memcpy or memset - calls or, on some targets, inline expansion thereof that sometimes need - to use specific hard registers. - - */ - if (stmt_ends_bb_p (stmt) + if (/* We can't sink statements that end basic blocks without splitting + the incoming edge for the sink location to place it there. */ + stmt_ends_bb_p (stmt) + /* We can't sink statements with side effects, e.g. statements that + have volatile operands, or non-pure calls. */ || gimple_has_side_effects (stmt) - || gimple_has_volatile_ops (stmt) + /* We don't want to sink loads from memory. + We can't sink things that may be global stores, at least not + without calculating a lot more information, because we may cause + it to no longer be seen by an external routine that needs it + depending on where it gets moved to. */ || (gimple_vuse (stmt) && !gimple_vdef (stmt)) + /* Don't sink BLKmode assignments if current function has any local + explicit register variables, as BLKmode assignments may involve + memcpy or memset calls or, on some targets, inline expansion + thereof that sometimes need to use specific hard registers. */ || (cfun->has_local_explicit_reg_vars - && TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt))) == BLKmode)) + && TYPE_MODE (TREE_TYPE (stmt_lhs)) == BLKmode)) return false; + /* We can't sink across abnormal PHIs. */ if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (DEF_FROM_PTR (def_p))) return false; - FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES) { tree use = USE_FROM_PTR (use_p); @@ -334,8 +326,7 @@ statement_sink_location (gimple stmt, basic_block /* A killing definition is not a use. */ if (gimple_assign_single_p (use_stmt) && gimple_vdef (use_stmt) - && operand_equal_p (gimple_assign_lhs (stmt), - gimple_assign_lhs (use_stmt), 0)) + && operand_equal_p (stmt_lhs, gimple_assign_lhs (use_stmt), 0)) continue; if (gimple_code (use_stmt) != GIMPLE_PHI)