On Wed, 30 Sep 2015, Richard Biener wrote: > > This is the last patch in the series and it finally ditches the > stmt combining code from SCCVN which uses GENERIC. I've been sitting > on this for a while because of the "bad" interface that new mprts_hook > is but I couldn't think of a better way than completely refactoring > stmt folding into more C++ (and I'm not even sure how that end result > would look like). So rather than pondering on this forever the following > patch goes forward. > > Net result is that there will be hopefully no regressions (I know > about a few corner cases I found with plastering the code with asserts > but I do not consider them important) but progression both with regarding > to compile-time / memory-use and optimization (because the new code > is strictly more powerful, not relying on the has_constants heuristic). > > This is also the last major piece that was sitting on the > match-and-simplify branch. > > Bootstrapped on x86_64-unknown-linux-gnu, re-testing in progress.
This is the variant I committed. Richard. 2015-10-01 Richard Biener <rguent...@suse.de> * gimple-match.h (mprts_hook): Declare. * gimple-match.head.c (mprts_hook): Define. (maybe_push_res_to_seq): Use new hook. * gimple-fold.c (gimple_fold_stmt_to_constant_1): Likewise. * tree-ssa-sccvn.h (vn_ssa_aux::expr): Change to a gimple_seq. (vn_ssa_aux::has_constants): Remove. * tree-ssa-sccvn.c: Include gimple-match.h. (VN_INFO_GET): Assert we don't re-use SSA names. (vn_get_expr_for): Remove. (expr_has_constants): Likewise. (stmt_has_constants): Likewise. (simplify_binary_expression): Likewise. (simplify_unary_expression): Likewise. (vn_lookup_simplify_result): New hook. (visit_copy): Adjust. (visit_reference_op_call): Likewise. (visit_phi): Likewise. (visit_use): Likewise. (process_scc): Likewise. (init_scc_vn): Likewise. (visit_reference_op_load): Likewise. Use match-and-simplify and a gimple seq for inserted expressions. (try_to_simplify): Remove GENERIC stmt combining code. (sccvn_dom_walker::before_dom_children): Use match-and-simplify. * tree-ssa-pre.c (eliminate_insert): Adjust. (eliminate_dom_walker::before_dom_children): Likewise. * gcc.dg/tree-ssa/ssa-fre-7.c: Adjust. * gcc.dg/tree-ssa/ssa-fre-8.c: Likewise. Index: gcc/tree-ssa-sccvn.c =================================================================== *** gcc/tree-ssa-sccvn.c.orig 2015-09-30 15:00:30.636706575 +0200 --- gcc/tree-ssa-sccvn.c 2015-09-30 15:32:03.543978540 +0200 *************** along with GCC; see the file COPYING3. *** 58,63 **** --- 58,64 ---- #include "domwalk.h" #include "cgraph.h" #include "gimple-iterator.h" + #include "gimple-match.h" /* This algorithm is based on the SCC algorithm presented by Keith Cooper and L. Taylor Simpson in "SCC-Based Value numbering" *************** VN_INFO_GET (tree name) *** 401,406 **** --- 402,409 ---- { vn_ssa_aux_t newinfo; + gcc_assert (SSA_NAME_VERSION (name) >= vn_ssa_aux_table.length () + || vn_ssa_aux_table[SSA_NAME_VERSION (name)] == NULL); newinfo = XOBNEW (&vn_ssa_aux_obstack, struct vn_ssa_aux); memset (newinfo, 0, sizeof (struct vn_ssa_aux)); if (SSA_NAME_VERSION (name) >= vn_ssa_aux_table.length ()) *************** VN_INFO_GET (tree name) *** 410,501 **** } - /* Get the representative expression for the SSA_NAME NAME. Returns - the representative SSA_NAME if there is no expression associated with it. */ - - tree - vn_get_expr_for (tree name) - { - vn_ssa_aux_t vn = VN_INFO (name); - gimple *def_stmt; - tree expr = NULL_TREE; - enum tree_code code; - - if (vn->valnum == VN_TOP) - return name; - - /* If the value-number is a constant it is the representative - expression. */ - if (TREE_CODE (vn->valnum) != SSA_NAME) - return vn->valnum; - - /* Get to the information of the value of this SSA_NAME. */ - vn = VN_INFO (vn->valnum); - - /* If the value-number is a constant it is the representative - expression. */ - if (TREE_CODE (vn->valnum) != SSA_NAME) - return vn->valnum; - - /* Else if we have an expression, return it. */ - if (vn->expr != NULL_TREE) - return vn->expr; - - /* Otherwise use the defining statement to build the expression. */ - def_stmt = SSA_NAME_DEF_STMT (vn->valnum); - - /* If the value number is not an assignment use it directly. */ - if (!is_gimple_assign (def_stmt)) - return vn->valnum; - - /* Note that we can valueize here because we clear the cached - simplified expressions after each optimistic iteration. */ - code = gimple_assign_rhs_code (def_stmt); - switch (TREE_CODE_CLASS (code)) - { - case tcc_reference: - if ((code == REALPART_EXPR - || code == IMAGPART_EXPR - || code == VIEW_CONVERT_EXPR) - && TREE_CODE (TREE_OPERAND (gimple_assign_rhs1 (def_stmt), - 0)) == SSA_NAME) - expr = fold_build1 (code, - gimple_expr_type (def_stmt), - vn_valueize (TREE_OPERAND - (gimple_assign_rhs1 (def_stmt), 0))); - break; - - case tcc_unary: - expr = fold_build1 (code, - gimple_expr_type (def_stmt), - vn_valueize (gimple_assign_rhs1 (def_stmt))); - break; - - case tcc_binary: - expr = fold_build2 (code, - gimple_expr_type (def_stmt), - vn_valueize (gimple_assign_rhs1 (def_stmt)), - vn_valueize (gimple_assign_rhs2 (def_stmt))); - break; - - case tcc_exceptional: - if (code == CONSTRUCTOR - && TREE_CODE - (TREE_TYPE (gimple_assign_rhs1 (def_stmt))) == VECTOR_TYPE) - expr = gimple_assign_rhs1 (def_stmt); - break; - - default:; - } - if (expr == NULL_TREE) - return vn->valnum; - - /* Cache the expression. */ - vn->expr = expr; - - return expr; - } - /* Return the vn_kind the expression computed by the stmt should be associated with. */ --- 413,418 ---- *************** vn_nary_op_lookup_stmt (gimple *stmt, vn *** 2685,2690 **** --- 2602,2619 ---- return vn_nary_op_lookup_1 (vno1, vnresult); } + /* Hook for maybe_push_res_to_seq, lookup the expression in the VN tables. */ + + static tree + vn_lookup_simplify_result (code_helper rcode, tree type, tree *ops) + { + if (!rcode.is_tree_code ()) + return NULL_TREE; + vn_nary_op_t vnresult = NULL; + return vn_nary_op_lookup_pieces (TREE_CODE_LENGTH ((tree_code) rcode), + (tree_code) rcode, type, ops, &vnresult); + } + /* Allocate a vn_nary_op_t with LENGTH operands on STACK. */ static vn_nary_op_t *************** defs_to_varying (gimple *stmt) *** 3047,3066 **** return changed; } - static bool expr_has_constants (tree expr); - /* Visit a copy between LHS and RHS, return true if the value number changed. */ static bool visit_copy (tree lhs, tree rhs) { ! /* The copy may have a more interesting constant filled expression ! (we don't, since we know our RHS is just an SSA name). */ ! VN_INFO (lhs)->has_constants = VN_INFO (rhs)->has_constants; ! VN_INFO (lhs)->expr = VN_INFO (rhs)->expr; ! ! /* And finally valueize. */ rhs = SSA_VAL (rhs); return set_ssa_val_to (lhs, rhs); --- 2976,2988 ---- return changed; } /* Visit a copy between LHS and RHS, return true if the value number changed. */ static bool visit_copy (tree lhs, tree rhs) { ! /* Valueize. */ rhs = SSA_VAL (rhs); return set_ssa_val_to (lhs, rhs); *************** visit_reference_op_call (tree lhs, gcall *** 3111,3122 **** vnresult->result = lhs; if (vnresult->result && lhs) ! { ! changed |= set_ssa_val_to (lhs, vnresult->result); ! ! if (VN_INFO (vnresult->result)->has_constants) ! VN_INFO (lhs)->has_constants = true; ! } } else { --- 3033,3039 ---- vnresult->result = lhs; if (vnresult->result && lhs) ! changed |= set_ssa_val_to (lhs, vnresult->result); } else { *************** visit_reference_op_load (tree lhs, tree *** 3172,3204 **** of VIEW_CONVERT_EXPR <TREE_TYPE (result)> (result). So first simplify and lookup this expression to see if it is already available. */ ! tree val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (op), result); ! if ((CONVERT_EXPR_P (val) ! || TREE_CODE (val) == VIEW_CONVERT_EXPR) ! && TREE_CODE (TREE_OPERAND (val, 0)) == SSA_NAME) ! { ! tree tem = vn_get_expr_for (TREE_OPERAND (val, 0)); ! if ((CONVERT_EXPR_P (tem) ! || TREE_CODE (tem) == VIEW_CONVERT_EXPR) ! && (tem = fold_unary_ignore_overflow (TREE_CODE (val), ! TREE_TYPE (val), tem))) ! val = tem; ! } ! result = val; ! if (!is_gimple_min_invariant (val) ! && TREE_CODE (val) != SSA_NAME) ! result = vn_nary_op_lookup (val, NULL); ! /* If the expression is not yet available, value-number lhs to ! a new SSA_NAME we create. */ ! if (!result) ! { ! result = make_temp_ssa_name (TREE_TYPE (lhs), gimple_build_nop (), ! "vntemp"); /* Initialize value-number information properly. */ VN_INFO_GET (result)->valnum = result; VN_INFO (result)->value_id = get_next_value_id (); ! VN_INFO (result)->expr = val; ! VN_INFO (result)->has_constants = expr_has_constants (val); VN_INFO (result)->needs_insertion = true; /* As all "inserted" statements are singleton SCCs, insert to the valid table. This is strictly needed to --- 3089,3126 ---- of VIEW_CONVERT_EXPR <TREE_TYPE (result)> (result). So first simplify and lookup this expression to see if it is already available. */ ! gimple_seq stmts = NULL; ! mprts_hook = vn_lookup_simplify_result; ! tree val = gimple_simplify (VIEW_CONVERT_EXPR, TREE_TYPE (op), ! result, &stmts, vn_valueize); ! mprts_hook = NULL; ! if (!val) ! { ! val = vn_nary_op_lookup_pieces (1, VIEW_CONVERT_EXPR, ! TREE_TYPE (op), &result, NULL); ! if (!val) ! { ! val = make_ssa_name (TREE_TYPE (op)); ! gimple *new_stmt = gimple_build_assign (val, VIEW_CONVERT_EXPR, ! build1 (VIEW_CONVERT_EXPR, ! TREE_TYPE (op), ! result)); ! gimple_seq_add_stmt_without_update (&stmts, new_stmt); ! } ! } ! if (gimple_seq_empty_p (stmts)) ! /* The expression is already available. */ ! result = val; ! else ! { ! gcc_assert (gimple_seq_singleton_p (stmts)); ! /* The expression is not yet available, value-number lhs to ! the new SSA_NAME we created. */ ! result = val; /* Initialize value-number information properly. */ VN_INFO_GET (result)->valnum = result; VN_INFO (result)->value_id = get_next_value_id (); ! VN_INFO (result)->expr = stmts; VN_INFO (result)->needs_insertion = true; /* As all "inserted" statements are singleton SCCs, insert to the valid table. This is strictly needed to *************** visit_reference_op_load (tree lhs, tree *** 3210,3241 **** if (current_info == optimistic_info) { current_info = valid_info; ! vn_nary_op_insert (val, result); current_info = optimistic_info; } else ! vn_nary_op_insert (val, result); if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Inserting name "); print_generic_expr (dump_file, result, 0); fprintf (dump_file, " for expression "); ! print_generic_expr (dump_file, val, 0); fprintf (dump_file, "\n"); } } } if (result) ! { ! changed = set_ssa_val_to (lhs, result); ! if (TREE_CODE (result) == SSA_NAME ! && VN_INFO (result)->has_constants) ! { ! VN_INFO (lhs)->expr = VN_INFO (result)->expr; ! VN_INFO (lhs)->has_constants = true; ! } ! } else { changed = set_ssa_val_to (lhs, lhs); --- 3132,3156 ---- if (current_info == optimistic_info) { current_info = valid_info; ! vn_nary_op_insert_stmt (gimple_seq_first_stmt (stmts), result); current_info = optimistic_info; } else ! vn_nary_op_insert_stmt (gimple_seq_first_stmt (stmts), result); if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Inserting name "); print_generic_expr (dump_file, result, 0); fprintf (dump_file, " for expression "); ! print_gimple_expr (dump_file, gimple_seq_first_stmt (stmts), ! 0, TDF_SLIM); fprintf (dump_file, "\n"); } } } if (result) ! changed = set_ssa_val_to (lhs, result); else { changed = set_ssa_val_to (lhs, lhs); *************** visit_phi (gimple *phi) *** 3401,3608 **** else { vn_phi_insert (phi, PHI_RESULT (phi)); - VN_INFO (PHI_RESULT (phi))->has_constants = false; - VN_INFO (PHI_RESULT (phi))->expr = PHI_RESULT (phi); changed = set_ssa_val_to (PHI_RESULT (phi), PHI_RESULT (phi)); } return changed; } - /* Return true if EXPR contains constants. */ - - static bool - expr_has_constants (tree expr) - { - switch (TREE_CODE_CLASS (TREE_CODE (expr))) - { - case tcc_unary: - return is_gimple_min_invariant (TREE_OPERAND (expr, 0)); - - case tcc_binary: - return is_gimple_min_invariant (TREE_OPERAND (expr, 0)) - || is_gimple_min_invariant (TREE_OPERAND (expr, 1)); - /* Constants inside reference ops are rarely interesting, but - it can take a lot of looking to find them. */ - case tcc_reference: - case tcc_declaration: - return false; - default: - return is_gimple_min_invariant (expr); - } - return false; - } - - /* Return true if STMT contains constants. */ - - static bool - stmt_has_constants (gimple *stmt) - { - tree tem; - - if (gimple_code (stmt) != GIMPLE_ASSIGN) - return false; - - switch (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))) - { - case GIMPLE_TERNARY_RHS: - tem = gimple_assign_rhs3 (stmt); - if (TREE_CODE (tem) == SSA_NAME) - tem = SSA_VAL (tem); - if (is_gimple_min_invariant (tem)) - return true; - /* Fallthru. */ - - case GIMPLE_BINARY_RHS: - tem = gimple_assign_rhs2 (stmt); - if (TREE_CODE (tem) == SSA_NAME) - tem = SSA_VAL (tem); - if (is_gimple_min_invariant (tem)) - return true; - /* Fallthru. */ - - case GIMPLE_SINGLE_RHS: - /* Constants inside reference ops are rarely interesting, but - it can take a lot of looking to find them. */ - case GIMPLE_UNARY_RHS: - tem = gimple_assign_rhs1 (stmt); - if (TREE_CODE (tem) == SSA_NAME) - tem = SSA_VAL (tem); - return is_gimple_min_invariant (tem); - - default: - gcc_unreachable (); - } - return false; - } - - /* Simplify the binary expression RHS, and return the result if - simplified. */ - - static tree - simplify_binary_expression (gimple *stmt) - { - tree result = NULL_TREE; - tree op0 = gimple_assign_rhs1 (stmt); - tree op1 = gimple_assign_rhs2 (stmt); - enum tree_code code = gimple_assign_rhs_code (stmt); - - /* This will not catch every single case we could combine, but will - catch those with constants. The goal here is to simultaneously - combine constants between expressions, but avoid infinite - expansion of expressions during simplification. */ - op0 = vn_valueize (op0); - if (TREE_CODE (op0) == SSA_NAME - && (VN_INFO (op0)->has_constants - || TREE_CODE_CLASS (code) == tcc_comparison - || code == COMPLEX_EXPR)) - op0 = vn_get_expr_for (op0); - - op1 = vn_valueize (op1); - if (TREE_CODE (op1) == SSA_NAME - && (VN_INFO (op1)->has_constants - || code == COMPLEX_EXPR)) - op1 = vn_get_expr_for (op1); - - /* Pointer plus constant can be represented as invariant address. - Do so to allow further propatation, see also tree forwprop. */ - if (code == POINTER_PLUS_EXPR - && tree_fits_uhwi_p (op1) - && TREE_CODE (op0) == ADDR_EXPR - && is_gimple_min_invariant (op0)) - return build_invariant_address (TREE_TYPE (op0), - TREE_OPERAND (op0, 0), - tree_to_uhwi (op1)); - - /* Avoid folding if nothing changed. */ - if (op0 == gimple_assign_rhs1 (stmt) - && op1 == gimple_assign_rhs2 (stmt)) - return NULL_TREE; - - fold_defer_overflow_warnings (); - - result = fold_binary (code, gimple_expr_type (stmt), op0, op1); - if (result) - STRIP_USELESS_TYPE_CONVERSION (result); - - fold_undefer_overflow_warnings (result && valid_gimple_rhs_p (result), - stmt, 0); - - /* Make sure result is not a complex expression consisting - of operators of operators (IE (a + b) + (a + c)) - Otherwise, we will end up with unbounded expressions if - fold does anything at all. */ - if (result && valid_gimple_rhs_p (result)) - return result; - - return NULL_TREE; - } - - /* Simplify the unary expression RHS, and return the result if - simplified. */ - - static tree - simplify_unary_expression (gassign *stmt) - { - tree result = NULL_TREE; - tree orig_op0, op0 = gimple_assign_rhs1 (stmt); - enum tree_code code = gimple_assign_rhs_code (stmt); - - /* We handle some tcc_reference codes here that are all - GIMPLE_ASSIGN_SINGLE codes. */ - if (code == REALPART_EXPR - || code == IMAGPART_EXPR - || code == VIEW_CONVERT_EXPR - || code == BIT_FIELD_REF) - op0 = TREE_OPERAND (op0, 0); - - orig_op0 = op0; - op0 = vn_valueize (op0); - if (TREE_CODE (op0) == SSA_NAME) - { - if (VN_INFO (op0)->has_constants) - op0 = vn_get_expr_for (op0); - else if (CONVERT_EXPR_CODE_P (code) - || code == REALPART_EXPR - || code == IMAGPART_EXPR - || code == VIEW_CONVERT_EXPR - || code == BIT_FIELD_REF) - { - /* We want to do tree-combining on conversion-like expressions. - Make sure we feed only SSA_NAMEs or constants to fold though. */ - tree tem = vn_get_expr_for (op0); - if (UNARY_CLASS_P (tem) - || BINARY_CLASS_P (tem) - || TREE_CODE (tem) == VIEW_CONVERT_EXPR - || TREE_CODE (tem) == SSA_NAME - || TREE_CODE (tem) == CONSTRUCTOR - || is_gimple_min_invariant (tem)) - op0 = tem; - } - } - - /* Avoid folding if nothing changed, but remember the expression. */ - if (op0 == orig_op0) - return NULL_TREE; - - if (code == BIT_FIELD_REF) - { - tree rhs = gimple_assign_rhs1 (stmt); - result = fold_ternary (BIT_FIELD_REF, TREE_TYPE (rhs), - op0, TREE_OPERAND (rhs, 1), TREE_OPERAND (rhs, 2)); - } - else - result = fold_unary_ignore_overflow (code, gimple_expr_type (stmt), op0); - if (result) - { - STRIP_USELESS_TYPE_CONVERSION (result); - if (valid_gimple_rhs_p (result)) - return result; - } - - return NULL_TREE; - } - /* Try to simplify RHS using equivalences and constant folding. */ static tree --- 3316,3327 ---- *************** try_to_simplify (gassign *stmt) *** 3617,3651 **** return NULL_TREE; /* First try constant folding based on our current lattice. */ tem = gimple_fold_stmt_to_constant_1 (stmt, vn_valueize, vn_valueize); if (tem && (TREE_CODE (tem) == SSA_NAME || is_gimple_min_invariant (tem))) return tem; - /* If that didn't work try combining multiple statements. */ - switch (TREE_CODE_CLASS (code)) - { - case tcc_reference: - /* Fallthrough for some unary codes that can operate on registers. */ - if (!(code == REALPART_EXPR - || code == IMAGPART_EXPR - || code == VIEW_CONVERT_EXPR - || code == BIT_FIELD_REF)) - break; - /* We could do a little more with unary ops, if they expand - into binary ops, but it's debatable whether it is worth it. */ - case tcc_unary: - return simplify_unary_expression (stmt); - - case tcc_comparison: - case tcc_binary: - return simplify_binary_expression (stmt); - - default: - break; - } - return NULL_TREE; } --- 3336,3349 ---- return NULL_TREE; /* First try constant folding based on our current lattice. */ + mprts_hook = vn_lookup_simplify_result; tem = gimple_fold_stmt_to_constant_1 (stmt, vn_valueize, vn_valueize); + mprts_hook = NULL; if (tem && (TREE_CODE (tem) == SSA_NAME || is_gimple_min_invariant (tem))) return tem; return NULL_TREE; } *************** visit_use (tree use) *** 3703,3713 **** print_gimple_expr (dump_file, stmt, 0, 0); fprintf (dump_file, " simplified to "); print_generic_expr (dump_file, simplified, 0); ! if (TREE_CODE (lhs) == SSA_NAME) ! fprintf (dump_file, " has constants %d\n", ! expr_has_constants (simplified)); ! else ! fprintf (dump_file, "\n"); } } /* Setting value numbers to constants will occasionally --- 3401,3407 ---- print_gimple_expr (dump_file, stmt, 0, 0); fprintf (dump_file, " simplified to "); print_generic_expr (dump_file, simplified, 0); ! fprintf (dump_file, "\n"); } } /* Setting value numbers to constants will occasionally *************** visit_use (tree use) *** 3718,3725 **** && is_gimple_min_invariant (simplified) && TREE_CODE (lhs) == SSA_NAME) { - VN_INFO (lhs)->expr = simplified; - VN_INFO (lhs)->has_constants = true; changed = set_ssa_val_to (lhs, simplified); goto done; } --- 3412,3417 ---- *************** visit_use (tree use) *** 3730,3758 **** changed = visit_copy (lhs, simplified); goto done; } - else if (simplified) - { - if (TREE_CODE (lhs) == SSA_NAME) - { - VN_INFO (lhs)->has_constants = expr_has_constants (simplified); - /* We have to unshare the expression or else - valuizing may change the IL stream. */ - VN_INFO (lhs)->expr = unshare_expr (simplified); - } - } - else if (stmt_has_constants (stmt) - && TREE_CODE (lhs) == SSA_NAME) - VN_INFO (lhs)->has_constants = true; - else if (TREE_CODE (lhs) == SSA_NAME) - { - /* We reset expr and constantness here because we may - have been value numbering optimistically, and - iterating. They may become non-constant in this case, - even if they were optimistically constant. */ - - VN_INFO (lhs)->has_constants = false; - VN_INFO (lhs)->expr = NULL_TREE; - } if ((TREE_CODE (lhs) == SSA_NAME /* We can substitute SSA_NAMEs that are live over --- 3422,3427 ---- *************** visit_use (tree use) *** 3777,3783 **** || (simplified && is_gimple_min_invariant (simplified))) { - VN_INFO (lhs)->has_constants = true; if (simplified) changed = set_ssa_val_to (lhs, simplified); else --- 3446,3451 ---- *************** visit_use (tree use) *** 3840,3850 **** print_gimple_expr (dump_file, stmt, 0, 0); fprintf (dump_file, " simplified to "); print_generic_expr (dump_file, simplified, 0); ! if (TREE_CODE (lhs) == SSA_NAME) ! fprintf (dump_file, " has constants %d\n", ! expr_has_constants (simplified)); ! else ! fprintf (dump_file, "\n"); } } /* Setting value numbers to constants will occasionally --- 3508,3514 ---- print_gimple_expr (dump_file, stmt, 0, 0); fprintf (dump_file, " simplified to "); print_generic_expr (dump_file, simplified, 0); ! fprintf (dump_file, "\n"); } } /* Setting value numbers to constants will occasionally *************** visit_use (tree use) *** 3854,3861 **** if (simplified && is_gimple_min_invariant (simplified)) { - VN_INFO (lhs)->expr = simplified; - VN_INFO (lhs)->has_constants = true; changed = set_ssa_val_to (lhs, simplified); if (gimple_vdef (stmt)) changed |= set_ssa_val_to (gimple_vdef (stmt), --- 3518,3523 ---- *************** visit_use (tree use) *** 3873,3890 **** } else { - if (stmt_has_constants (stmt)) - VN_INFO (lhs)->has_constants = true; - else - { - /* We reset expr and constantness here because we may - have been value numbering optimistically, and - iterating. They may become non-constant in this case, - even if they were optimistically constant. */ - VN_INFO (lhs)->has_constants = false; - VN_INFO (lhs)->expr = NULL_TREE; - } - if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)) { changed = defs_to_varying (stmt); --- 3535,3540 ---- *************** process_scc (vec<tree> scc) *** 4083,4089 **** optimistic_info->phis_pool->release (); optimistic_info->references_pool->release (); FOR_EACH_VEC_ELT (scc, i, var) ! VN_INFO (var)->expr = NULL_TREE; FOR_EACH_VEC_ELT (scc, i, var) changed |= visit_use (var); } --- 3733,3740 ---- optimistic_info->phis_pool->release (); optimistic_info->references_pool->release (); FOR_EACH_VEC_ELT (scc, i, var) ! gcc_assert (!VN_INFO (var)->needs_insertion ! && VN_INFO (var)->expr == NULL); FOR_EACH_VEC_ELT (scc, i, var) changed |= visit_use (var); } *************** init_scc_vn (void) *** 4338,4344 **** continue; VN_INFO_GET (name)->valnum = VN_TOP; ! VN_INFO (name)->expr = NULL_TREE; VN_INFO (name)->value_id = 0; if (!SSA_NAME_IS_DEFAULT_DEF (name)) --- 3989,3996 ---- continue; VN_INFO_GET (name)->valnum = VN_TOP; ! VN_INFO (name)->needs_insertion = false; ! VN_INFO (name)->expr = NULL; VN_INFO (name)->value_id = 0; if (!SSA_NAME_IS_DEFAULT_DEF (name)) *************** sccvn_dom_walker::before_dom_children (b *** 4692,4714 **** { case GIMPLE_COND: { ! tree lhs = gimple_cond_lhs (stmt); ! tree rhs = gimple_cond_rhs (stmt); ! /* Work hard in computing the condition and take into account ! the valueization of the defining stmt. */ ! if (TREE_CODE (lhs) == SSA_NAME) ! lhs = vn_get_expr_for (lhs); ! if (TREE_CODE (rhs) == SSA_NAME) ! rhs = vn_get_expr_for (rhs); ! val = fold_binary (gimple_cond_code (stmt), ! boolean_type_node, lhs, rhs); /* If that didn't simplify to a constant see if we have recorded temporary expressions from taken edges. */ if (!val || TREE_CODE (val) != INTEGER_CST) { tree ops[2]; ! ops[0] = gimple_cond_lhs (stmt); ! ops[1] = gimple_cond_rhs (stmt); val = vn_nary_op_lookup_pieces (2, gimple_cond_code (stmt), boolean_type_node, ops, NULL); } --- 4344,4361 ---- { case GIMPLE_COND: { ! tree lhs = vn_valueize (gimple_cond_lhs (stmt)); ! tree rhs = vn_valueize (gimple_cond_rhs (stmt)); ! val = gimple_simplify (gimple_cond_code (stmt), ! boolean_type_node, lhs, rhs, ! NULL, vn_valueize); /* If that didn't simplify to a constant see if we have recorded temporary expressions from taken edges. */ if (!val || TREE_CODE (val) != INTEGER_CST) { tree ops[2]; ! ops[0] = lhs; ! ops[1] = rhs; val = vn_nary_op_lookup_pieces (2, gimple_cond_code (stmt), boolean_type_node, ops, NULL); } Index: gcc/gimple-match-head.c =================================================================== *** gcc/gimple-match-head.c.orig 2015-09-30 15:00:30.636706575 +0200 --- gcc/gimple-match-head.c 2015-09-30 15:22:48.939766818 +0200 *************** maybe_build_generic_op (enum tree_code c *** 293,298 **** --- 293,300 ---- } } + tree (*mprts_hook) (code_helper, tree, tree *); + /* Push the exploded expression described by RCODE, TYPE and OPS as a statement to SEQ if necessary and return a gimple value denoting the value of the expression. If RES is not NULL *************** maybe_push_res_to_seq (code_helper rcode *** 310,315 **** --- 312,323 ---- || ((tree_code) rcode) == ADDR_EXPR) && is_gimple_val (ops[0])) return ops[0]; + if (mprts_hook) + { + tree tem = mprts_hook (rcode, type, ops); + if (tem) + return tem; + } if (!seq) return NULL_TREE; /* Play safe and do not allow abnormals to be mentioned in Index: gcc/gimple-match.h =================================================================== *** gcc/gimple-match.h.orig 2015-09-30 15:00:30.636706575 +0200 --- gcc/gimple-match.h 2015-09-30 15:22:48.939766818 +0200 *************** private: *** 40,45 **** --- 40,47 ---- int rep; }; + extern tree (*mprts_hook) (code_helper, tree, tree *); + bool gimple_simplify (gimple *, code_helper *, tree *, gimple_seq *, tree (*)(tree), tree (*)(tree)); tree maybe_push_res_to_seq (code_helper, tree, tree *, Index: gcc/tree-ssa-sccvn.h =================================================================== *** gcc/tree-ssa-sccvn.h.orig 2015-09-30 15:00:30.636706575 +0200 --- gcc/tree-ssa-sccvn.h 2015-09-30 15:22:48.940766830 +0200 *************** typedef struct vn_ssa_aux *** 165,172 **** { /* Value number. This may be an SSA name or a constant. */ tree valnum; ! /* Representative expression, if not a direct constant. */ ! tree expr; /* Unique identifier that all expressions with the same value have. */ unsigned int value_id; --- 165,172 ---- { /* Value number. This may be an SSA name or a constant. */ tree valnum; ! /* Statements to insert if needs_insertion is true. */ ! gimple_seq expr; /* Unique identifier that all expressions with the same value have. */ unsigned int value_id; *************** typedef struct vn_ssa_aux *** 177,184 **** unsigned visited : 1; unsigned on_sccstack : 1; - /* Whether the representative expression contains constants. */ - unsigned has_constants : 1; /* Whether the SSA_NAME has been value numbered already. This is only saying whether visit_use has been called on it at least once. It cannot be used to avoid visitation for SSA_NAME's --- 177,182 ---- Index: gcc/tree-ssa-pre.c =================================================================== *** gcc/tree-ssa-pre.c.orig 2015-09-30 15:00:30.636706575 +0200 --- gcc/tree-ssa-pre.c 2015-09-30 15:22:48.941766841 +0200 *************** eliminate_push_avail (tree op) *** 3953,3973 **** static tree eliminate_insert (gimple_stmt_iterator *gsi, tree val) { ! tree expr = vn_get_expr_for (val); ! if (!CONVERT_EXPR_P (expr) ! && TREE_CODE (expr) != VIEW_CONVERT_EXPR) return NULL_TREE; ! tree op = TREE_OPERAND (expr, 0); tree leader = TREE_CODE (op) == SSA_NAME ? eliminate_avail (op) : op; if (!leader) return NULL_TREE; ! tree res = make_temp_ssa_name (TREE_TYPE (val), NULL, "pretmp"); ! gassign *tem = gimple_build_assign (res, ! fold_build1 (TREE_CODE (expr), ! TREE_TYPE (expr), leader)); ! gsi_insert_before (gsi, tem, GSI_SAME_STMT); VN_INFO_GET (res)->valnum = val; if (TREE_CODE (leader) == SSA_NAME) --- 3953,3975 ---- static tree eliminate_insert (gimple_stmt_iterator *gsi, tree val) { ! gimple *stmt = gimple_seq_first_stmt (VN_INFO (val)->expr); ! if (!is_gimple_assign (stmt) ! || (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt)) ! && gimple_assign_rhs_code (stmt) != VIEW_CONVERT_EXPR)) return NULL_TREE; ! tree op = gimple_assign_rhs1 (stmt); ! if (gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR) ! op = TREE_OPERAND (op, 0); tree leader = TREE_CODE (op) == SSA_NAME ? eliminate_avail (op) : op; if (!leader) return NULL_TREE; ! gimple_seq stmts = NULL; ! tree res = gimple_build (&stmts, gimple_assign_rhs_code (stmt), ! TREE_TYPE (val), leader); ! gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); VN_INFO_GET (res)->valnum = val; if (TREE_CODE (leader) == SSA_NAME) *************** eliminate_insert (gimple_stmt_iterator * *** 3977,3983 **** if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Inserted "); ! print_gimple_stmt (dump_file, tem, 0, 0); } return res; --- 3979,3985 ---- if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Inserted "); ! print_gimple_stmt (dump_file, SSA_NAME_DEF_STMT (res), 0, 0); } return res; *************** eliminate_dom_walker::before_dom_childre *** 4101,4107 **** if (val != VN_TOP && TREE_CODE (val) == SSA_NAME && VN_INFO (val)->needs_insertion ! && VN_INFO (val)->expr != NULL_TREE && (sprime = eliminate_insert (&gsi, val)) != NULL_TREE) eliminate_push_avail (sprime); } --- 4103,4109 ---- if (val != VN_TOP && TREE_CODE (val) == SSA_NAME && VN_INFO (val)->needs_insertion ! && VN_INFO (val)->expr != NULL && (sprime = eliminate_insert (&gsi, val)) != NULL_TREE) eliminate_push_avail (sprime); } Index: gcc/gimple-fold.c =================================================================== *** gcc/gimple-fold.c.orig 2015-09-30 15:00:30.636706575 +0200 --- gcc/gimple-fold.c 2015-09-30 15:22:48.942766852 +0200 *************** gimple_fold_stmt_to_constant_1 (gimple * *** 4883,4904 **** edges if there are intermediate VARYING defs. For this reason do not follow SSA edges here even though SCCVN can technically just deal fine with that. */ ! if (gimple_simplify (stmt, &rcode, ops, NULL, gvalueize, valueize) ! && rcode.is_tree_code () ! && (TREE_CODE_LENGTH ((tree_code) rcode) == 0 ! || ((tree_code) rcode) == ADDR_EXPR) ! && is_gimple_val (ops[0])) { ! tree res = ops[0]; ! if (dump_file && dump_flags & TDF_DETAILS) { ! fprintf (dump_file, "Match-and-simplified "); ! print_gimple_expr (dump_file, stmt, 0, TDF_SLIM); ! fprintf (dump_file, " to "); ! print_generic_expr (dump_file, res, 0); ! fprintf (dump_file, "\n"); } - return res; } location_t loc = gimple_location (stmt); --- 4883,4910 ---- edges if there are intermediate VARYING defs. For this reason do not follow SSA edges here even though SCCVN can technically just deal fine with that. */ ! if (gimple_simplify (stmt, &rcode, ops, NULL, gvalueize, valueize)) { ! tree res = NULL_TREE; ! if (rcode.is_tree_code () ! && (TREE_CODE_LENGTH ((tree_code) rcode) == 0 ! || ((tree_code) rcode) == ADDR_EXPR) ! && is_gimple_val (ops[0])) ! res = ops[0]; ! else if (mprts_hook) ! res = mprts_hook (rcode, gimple_expr_type (stmt), ops); ! if (res) { ! if (dump_file && dump_flags & TDF_DETAILS) ! { ! fprintf (dump_file, "Match-and-simplified "); ! print_gimple_expr (dump_file, stmt, 0, TDF_SLIM); ! fprintf (dump_file, " to "); ! print_generic_expr (dump_file, res, 0); ! fprintf (dump_file, "\n"); ! } ! return res; } } location_t loc = gimple_location (stmt); Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-7.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-7.c.orig 2015-09-30 15:35:37.715366242 +0200 --- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-7.c 2015-09-30 15:35:48.739489118 +0200 *************** intflt foo(intflt j) *** 29,36 **** return a.u.k; } ! /* { dg-final { scan-tree-dump-times "Inserted pretmp" 1 "fre1" } } */ ! /* { dg-final { scan-tree-dump-times "Replaced a.u.f with pretmp" 3 "fre1" } } */ /* { dg-final { scan-tree-dump-times "Replaced a.u.k with j" 1 "fre1" } } */ /* { dg-final { scan-tree-dump "= VIEW_CONVERT_EXPR<float>\\\(j_" "fre1" } } */ /* { dg-final { scan-tree-dump "return j" "optimized" } } */ --- 29,36 ---- return a.u.k; } ! /* { dg-final { scan-tree-dump-times "Inserted" 1 "fre1" } } */ ! /* { dg-final { scan-tree-dump-times "Replaced a.u.f with" 3 "fre1" } } */ /* { dg-final { scan-tree-dump-times "Replaced a.u.k with j" 1 "fre1" } } */ /* { dg-final { scan-tree-dump "= VIEW_CONVERT_EXPR<float>\\\(j_" "fre1" } } */ /* { dg-final { scan-tree-dump "return j" "optimized" } } */ Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-8.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-8.c.orig 2015-09-30 15:35:37.724366342 +0200 --- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-8.c 2015-09-30 15:35:48.740489129 +0200 *************** intflt foo(int i, int b) *** 28,32 **** } } ! /* { dg-final { scan-tree-dump-times "Replaced u.f with pretmp" 2 "fre1" } } */ ! /* { dg-final { scan-tree-dump-times "Inserted pretmp" 2 "fre1" } } */ --- 28,32 ---- } } ! /* { dg-final { scan-tree-dump-times "Replaced u.f with" 2 "fre1" } } */ ! /* { dg-final { scan-tree-dump-times "Inserted" 2 "fre1" } } */