On Mon, 7 Jan 2013, Steven Bosscher wrote: > 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?
Comments below > 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; Instead of this ... > - /* 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; ... do stmt_lhs = DEF_FROM_PTR (def_p); which then also handles sinking single-def GIMPLE_ASMs ;) > - /* 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)) I suppose this also needs to handle stmt_lhs = call (); or the equivalent asm. Without handling asms thus adjust it to gimple_get_lhs as you did above, with handling asms instead use walk_stmt_load_store_addr_ops to walk all stores in the stmt. Thanks, Richard.