Mercurial > hg > CbC > CbC_gcc
diff gcc/tree-ssa-phiopt.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/tree-ssa-phiopt.c Fri Oct 27 22:46:09 2017 +0900 +++ b/gcc/tree-ssa-phiopt.c Thu Oct 25 07:37:49 2018 +0900 @@ -1,5 +1,5 @@ /* Optimization of PHI nodes by converting them into straightline code. - Copyright (C) 2004-2017 Free Software Foundation, Inc. + Copyright (C) 2004-2018 Free Software Foundation, Inc. This file is part of GCC. @@ -45,8 +45,9 @@ #include "tree-scalar-evolution.h" #include "tree-inline.h" #include "params.h" - -static unsigned int tree_ssa_phiopt_worker (bool, bool); +#include "case-cfn-macros.h" + +static unsigned int tree_ssa_phiopt_worker (bool, bool, bool); static bool conditional_replacement (basic_block, basic_block, edge, edge, gphi *, tree, tree); static gphi *factor_out_conditional_conversion (edge, edge, gphi *, tree, tree, @@ -57,6 +58,8 @@ 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); @@ -116,7 +119,7 @@ An interfacing issue of find_data_references_in_bb. */ loop_optimizer_init (LOOPS_NORMAL); scev_initialize (); - todo = tree_ssa_phiopt_worker (true, false); + todo = tree_ssa_phiopt_worker (true, false, false); scev_finalize (); loop_optimizer_finalize (); return todo; @@ -156,7 +159,7 @@ DO_HOIST_LOADS is true when we want to hoist adjacent loads out of diamond control flow patterns, false otherwise. */ static unsigned int -tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads) +tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) { basic_block bb; basic_block *bb_order; @@ -286,18 +289,19 @@ /* Value replacement can work with more than one PHI so try that first. */ - for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi)) - { - phi = as_a <gphi *> (gsi_stmt (gsi)); - arg0 = gimple_phi_arg_def (phi, e1->dest_idx); - arg1 = gimple_phi_arg_def (phi, e2->dest_idx); - if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1) == 2) - { - candorest = false; - cfgchanged = true; - break; - } - } + if (!early_p) + for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi)) + { + phi = as_a <gphi *> (gsi_stmt (gsi)); + arg0 = gimple_phi_arg_def (phi, e1->dest_idx); + arg1 = gimple_phi_arg_def (phi, e2->dest_idx); + if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1) == 2) + { + candorest = false; + cfgchanged = true; + break; + } + } if (!candorest) continue; @@ -328,10 +332,15 @@ } /* Do the replacement of conditional if it can be done. */ - if (conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + if (!early_p + && conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; + else if (!early_p + && 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; } @@ -548,8 +557,12 @@ /* Create the conversion stmt and insert it. */ if (convert_code == VIEW_CONVERT_EXPR) - temp = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (result), temp); - new_stmt = gimple_build_assign (result, convert_code, temp); + { + temp = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (result), temp); + new_stmt = gimple_build_assign (result, temp); + } + else + new_stmt = gimple_build_assign (result, convert_code, temp); gsi = gsi_after_labels (gimple_bb (phi)); gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); @@ -672,7 +685,6 @@ } replace_phi_edge_with_variable (cond_bb, e1, phi, new_var); - reset_flow_sensitive_info_in_bb (cond_bb); /* Note that we optimized this PHI. */ return true; @@ -690,12 +702,12 @@ { /* For arg = &p->i transform it to p, if possible. */ tree rhs1 = gimple_assign_rhs1 (stmt); - HOST_WIDE_INT offset; + poly_int64 offset; tree tem = get_addr_base_and_unit_offset (TREE_OPERAND (rhs1, 0), &offset); if (tem && TREE_CODE (tem) == MEM_REF - && (mem_ref_offset (tem) + offset) == 0) + && known_eq (mem_ref_offset (tem) + offset, 0)) { *arg = TREE_OPERAND (tem, 0); return true; @@ -904,7 +916,9 @@ gsi_next_nondebug (&gsi); if (!is_gimple_assign (stmt)) { - emtpy_or_with_defined_p = false; + if (gimple_code (stmt) != GIMPLE_PREDICT + && gimple_code (stmt) != GIMPLE_NOP) + emtpy_or_with_defined_p = false; continue; } /* Now try to adjust arg0 or arg1 according to the computation @@ -1138,22 +1152,22 @@ cond_rhs, false, rhs2)))))) { gsi = gsi_for_stmt (cond); + /* Moving ASSIGN might change VR of lhs, e.g. when moving u_6 + def-stmt in: + if (n_5 != 0) + goto <bb 3>; + else + goto <bb 4>; + + <bb 3>: + # RANGE [0, 4294967294] + u_6 = n_5 + 4294967295; + + <bb 4>: + # u_3 = PHI <u_6(3), 4294967295(2)> */ + reset_flow_sensitive_info (lhs); if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))) { - /* Moving ASSIGN might change VR of lhs, e.g. when moving u_6 - def-stmt in: - if (n_5 != 0) - goto <bb 3>; - else - goto <bb 4>; - - <bb 3>: - # RANGE [0, 4294967294] - u_6 = n_5 + 4294967295; - - <bb 4>: - # u_3 = PHI <u_6(3), 4294967295(2)> */ - SSA_NAME_RANGE_INFO (lhs) = NULL; /* If available, we can use VR of phi result at least. */ tree phires = gimple_phi_result (phi); struct range_info_def *phires_range_info @@ -1166,7 +1180,7 @@ for (int i = prep_cnt - 1; i >= 0; --i) { tree plhs = gimple_assign_lhs (prep_stmt[i]); - SSA_NAME_RANGE_INFO (plhs) = NULL; + reset_flow_sensitive_info (plhs); gsi_from = gsi_for_stmt (prep_stmt[i]); gsi_move_before (&gsi_from, &gsi); } @@ -1221,7 +1235,7 @@ { if (cmp == LT_EXPR) { - bool overflow; + wi::overflow_type overflow; wide_int alt = wi::sub (wi::to_wide (larger), 1, TYPE_SIGN (TREE_TYPE (larger)), &overflow); @@ -1230,7 +1244,7 @@ } else { - bool overflow; + wi::overflow_type overflow; wide_int alt = wi::add (wi::to_wide (larger), 1, TYPE_SIGN (TREE_TYPE (larger)), &overflow); @@ -1247,9 +1261,9 @@ Likewise larger >= CST is equivalent to larger > CST-1. */ if (TREE_CODE (smaller) == INTEGER_CST) { + wi::overflow_type overflow; if (cmp == GT_EXPR) { - bool overflow; wide_int alt = wi::add (wi::to_wide (smaller), 1, TYPE_SIGN (TREE_TYPE (smaller)), &overflow); @@ -1258,7 +1272,6 @@ } else { - bool overflow; wide_int alt = wi::sub (wi::to_wide (smaller), 1, TYPE_SIGN (TREE_TYPE (smaller)), &overflow); @@ -1490,6 +1503,8 @@ /* Move the statement from the middle block. */ gsi = gsi_last_bb (cond_bb); gsi_from = gsi_last_nondebug_bb (middle_bb); + reset_flow_sensitive_info (SINGLE_SSA_TREE_OPERAND (gsi_stmt (gsi_from), + SSA_OP_DEF)); gsi_move_before (&gsi_from, &gsi); } @@ -1508,8 +1523,141 @@ gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT); replace_phi_edge_with_variable (cond_bb, e1, phi, result); - reset_flow_sensitive_info_in_bb (cond_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); + } + + 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 + && gimple_cond_code (cond) != EQ_EXPR) + || !integer_zerop (gimple_cond_rhs (cond)) + || arg != gimple_cond_lhs (cond)) + return false; + + /* Canonicalize. */ + if ((e2->flags & EDGE_TRUE_VALUE + && gimple_cond_code (cond) == NE_EXPR) + || (e1->flags & EDGE_TRUE_VALUE + && gimple_cond_code (cond) == EQ_EXPR)) + { + std::swap (arg0, arg1); + std::swap (e1, e2); + } + + /* Check PHI arguments. */ + if (lhs != arg0 || !integer_zerop (arg1)) + 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; } @@ -1636,7 +1784,6 @@ } replace_phi_edge_with_variable (cond_bb, e1, phi, result); - reset_flow_sensitive_info_in_bb (cond_bb); /* Note that we optimized this PHI. */ return true; @@ -2032,6 +2179,36 @@ return true; } +/* Return the single store in BB with VDEF or NULL if there are + other stores in the BB or loads following the store. */ + +static gimple * +single_trailing_store_in_bb (basic_block bb, tree vdef) +{ + if (SSA_NAME_IS_DEFAULT_DEF (vdef)) + return NULL; + gimple *store = SSA_NAME_DEF_STMT (vdef); + if (gimple_bb (store) != bb + || gimple_code (store) == GIMPLE_PHI) + return NULL; + + /* Verify there is no other store in this BB. */ + if (!SSA_NAME_IS_DEFAULT_DEF (gimple_vuse (store)) + && gimple_bb (SSA_NAME_DEF_STMT (gimple_vuse (store))) == bb + && gimple_code (SSA_NAME_DEF_STMT (gimple_vuse (store))) != GIMPLE_PHI) + return NULL; + + /* Verify there is no load or store after the store. */ + use_operand_p use_p; + imm_use_iterator imm_iter; + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, gimple_vdef (store)) + if (USE_STMT (use_p) != store + && gimple_bb (USE_STMT (use_p)) == bb) + return NULL; + + return store; +} + /* Conditional store replacement. We already know that the recognized pattern looks like so: @@ -2058,8 +2235,6 @@ cond_if_else_store_replacement (basic_block then_bb, basic_block else_bb, basic_block join_bb) { - gimple *then_assign = last_and_only_stmt (then_bb); - gimple *else_assign = last_and_only_stmt (else_bb); vec<data_reference_p> then_datarefs, else_datarefs; vec<ddr_p> then_ddrs, else_ddrs; gimple *then_store, *else_store; @@ -2070,14 +2245,33 @@ tree then_lhs, else_lhs; basic_block blocks[3]; + /* Handle the case with single store in THEN_BB and ELSE_BB. That is + cheap enough to always handle as it allows us to elide dependence + checking. */ + gphi *vphi = NULL; + for (gphi_iterator si = gsi_start_phis (join_bb); !gsi_end_p (si); + gsi_next (&si)) + if (virtual_operand_p (gimple_phi_result (si.phi ()))) + { + vphi = si.phi (); + break; + } + if (!vphi) + return false; + tree then_vdef = PHI_ARG_DEF_FROM_EDGE (vphi, single_succ_edge (then_bb)); + tree else_vdef = PHI_ARG_DEF_FROM_EDGE (vphi, single_succ_edge (else_bb)); + gimple *then_assign = single_trailing_store_in_bb (then_bb, then_vdef); + if (then_assign) + { + gimple *else_assign = single_trailing_store_in_bb (else_bb, else_vdef); + if (else_assign) + return cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb, + then_assign, else_assign); + } + if (MAX_STORES_TO_SINK == 0) return false; - /* Handle the case with single statement in THEN_BB and ELSE_BB. */ - if (then_assign && else_assign) - return cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb, - then_assign, else_assign); - /* Find data references. */ then_datarefs.create (1); else_datarefs.create (1); @@ -2605,17 +2799,26 @@ { public: pass_phiopt (gcc::context *ctxt) - : gimple_opt_pass (pass_data_phiopt, ctxt) + : gimple_opt_pass (pass_data_phiopt, ctxt), early_p (false) {} /* opt_pass methods: */ opt_pass * clone () { return new pass_phiopt (m_ctxt); } + void set_pass_param (unsigned n, bool param) + { + gcc_assert (n == 0); + early_p = param; + } virtual bool gate (function *) { return flag_ssa_phiopt; } virtual unsigned int execute (function *) { - return tree_ssa_phiopt_worker (false, gate_hoist_loads ()); + return tree_ssa_phiopt_worker (false, + !early_p ? gate_hoist_loads () : false, + early_p); } +private: + bool early_p; }; // class pass_phiopt } // anon namespace