diff options
author | Kugan Vivekanandarajah <kuganv@linaro.org> | 2018-07-06 22:15:48 +0000 |
---|---|---|
committer | Kugan Vivekanandarajah <kugan@gcc.gnu.org> | 2018-07-06 22:15:48 +0000 |
commit | 58f12ec1437329c3269c6cafea98e22127d4bda8 (patch) | |
tree | 3e6be7f9ff32734c76314abc4064f4fa10c383d2 /gcc/tree-ssa-phiopt.c | |
parent | b8b31957e4c7e28fc44ae1b1ce658ba49ff1aa18 (diff) | |
download | gcc-58f12ec1437329c3269c6cafea98e22127d4bda8.zip gcc-58f12ec1437329c3269c6cafea98e22127d4bda8.tar.gz gcc-58f12ec1437329c3269c6cafea98e22127d4bda8.tar.bz2 |
tree-ssa-phiopt.c (cond_removal_in_popcount_pattern): New.
gcc/ChangeLog:
2018-07-06 Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
* tree-ssa-phiopt.c (cond_removal_in_popcount_pattern): New.
(tree_ssa_phiopt_worker): Call cond_removal_in_popcount_pattern.
gcc/testsuite/ChangeLog:
2018-07-06 Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
* gcc.dg/tree-ssa/phi-opt-16.c: New test.
* gcc.dg/tree-ssa/phi-opt-17.c: New test.
* gcc.dg/tree-ssa/phi-opt-18.c: New test.
* gcc.dg/tree-ssa/phi-opt-19.c: New test.
* gcc.dg/tree-ssa/popcount3.c: New test.
From-SVN: r262488
Diffstat (limited to 'gcc/tree-ssa-phiopt.c')
-rw-r--r-- | gcc/tree-ssa-phiopt.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index 8e94f6a..b2575f1 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-scalar-evolution.h" #include "tree-inline.h" #include "params.h" +#include "case-cfn-macros.h" static unsigned int tree_ssa_phiopt_worker (bool, bool); static bool conditional_replacement (basic_block, basic_block, @@ -57,6 +58,8 @@ static bool minmax_replacement (basic_block, basic_block, edge, edge, gimple *, tree, tree); static bool abs_replacement (basic_block, basic_block, edge, edge, gimple *, tree, tree); +static bool cond_removal_in_popcount_pattern (basic_block, basic_block, + edge, edge, gimple *, tree, tree); static bool cond_store_replacement (basic_block, basic_block, edge, edge, hash_set<tree> *); static bool cond_if_else_store_replacement (basic_block, basic_block, basic_block); @@ -332,6 +335,9 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads) cfgchanged = true; else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; + else if (cond_removal_in_popcount_pattern (bb, bb1, e1, e2, + phi, arg0, arg1)) + cfgchanged = true; else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; } @@ -1517,6 +1523,136 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, return true; } +/* Convert + + <bb 2> + if (b_4(D) != 0) + goto <bb 3> + else + goto <bb 4> + + <bb 3> + _2 = (unsigned long) b_4(D); + _9 = __builtin_popcountl (_2); + OR + _9 = __builtin_popcountl (b_4(D)); + + <bb 4> + c_12 = PHI <0(2), _9(3)> + + Into + <bb 2> + _2 = (unsigned long) b_4(D); + _9 = __builtin_popcountl (_2); + OR + _9 = __builtin_popcountl (b_4(D)); + + <bb 4> + c_12 = PHI <_9(2)> +*/ + +static bool +cond_removal_in_popcount_pattern (basic_block cond_bb, basic_block middle_bb, + edge e1, edge e2, + gimple *phi, tree arg0, tree arg1) +{ + gimple *cond; + gimple_stmt_iterator gsi, gsi_from; + gimple *popcount; + gimple *cast = NULL; + tree lhs, arg; + + /* Check that + _2 = (unsigned long) b_4(D); + _9 = __builtin_popcountl (_2); + OR + _9 = __builtin_popcountl (b_4(D)); + are the only stmts in the middle_bb. */ + + gsi = gsi_start_nondebug_after_labels_bb (middle_bb); + if (gsi_end_p (gsi)) + return false; + cast = gsi_stmt (gsi); + gsi_next_nondebug (&gsi); + if (!gsi_end_p (gsi)) + { + popcount = gsi_stmt (gsi); + gsi_next_nondebug (&gsi); + if (!gsi_end_p (gsi)) + return false; + } + else + { + popcount = cast; + cast = NULL; + } + + /* Check that we have a popcount builtin. */ + if (!is_gimple_call (popcount)) + return false; + combined_fn cfn = gimple_call_combined_fn (popcount); + switch (cfn) + { + CASE_CFN_POPCOUNT: + break; + default: + return false; + } + + arg = gimple_call_arg (popcount, 0); + lhs = gimple_get_lhs (popcount); + + if (cast) + { + /* We have a cast stmt feeding popcount builtin. */ + /* Check that we have a cast prior to that. */ + if (gimple_code (cast) != GIMPLE_ASSIGN + || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (cast))) + return false; + /* Result of the cast stmt is the argument to the builtin. */ + if (arg != gimple_assign_lhs (cast)) + return false; + arg = gimple_assign_rhs1 (cast); + } + + /* Canonicalize. */ + if (e2->flags & EDGE_TRUE_VALUE) + { + std::swap (arg0, arg1); + std::swap (e1, e2); + } + + /* Check PHI arguments. */ + if (lhs != arg0 || !integer_zerop (arg1)) + return false; + + cond = last_stmt (cond_bb); + + /* Cond_bb has a check for b_4 != 0 before calling the popcount + builtin. */ + if (gimple_code (cond) != GIMPLE_COND + || gimple_cond_code (cond) != NE_EXPR + || !integer_zerop (gimple_cond_rhs (cond)) + || arg != gimple_cond_lhs (cond)) + return false; + + /* And insert the popcount builtin and cast stmt before the cond_bb. */ + gsi = gsi_last_bb (cond_bb); + if (cast) + { + gsi_from = gsi_for_stmt (cast); + gsi_move_before (&gsi_from, &gsi); + reset_flow_sensitive_info (gimple_get_lhs (cast)); + } + gsi_from = gsi_for_stmt (popcount); + gsi_move_before (&gsi_from, &gsi); + reset_flow_sensitive_info (gimple_get_lhs (popcount)); + + /* Now update the PHI and remove unneeded bbs. */ + replace_phi_edge_with_variable (cond_bb, e2, phi, lhs); + return true; +} + /* The function absolute_replacement does the main work of doing the absolute replacement. Return true if the replacement is done. Otherwise return false. |