The stmt interface for gimple_simplify currently does not return "changed" when valueization would change it (it does if canonicalization does). This causes "missed" optimizations compared to the fold based code in fold_stmt.
Fixed as follows which runs into the issue that for variadic builtins type_num_arguments doesn't yield the number of arguments. So take that from the ops array state instead. Also special-case valueization when replacing a call with its valueized variant so it works in-place. Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2015-07-24 Richard Biener <rguent...@suse.de> * gimple-fold.c (replace_stmt_with_simplification): Special-case valueizing call operands. * gimple-match-head.c (maybe_push_res_to_seq): Take number of call arguments from ops array. (do_valueize): New function. (gimple_simplify): Return true if valueization changed any operand even if the result didn't simplify further. Index: gcc/gimple-fold.c =================================================================== *** gcc/gimple-fold.c (revision 226086) --- gcc/gimple-fold.c (working copy) *************** replace_stmt_with_simplification (gimple *** 3398,3403 **** --- 3398,3416 ---- return true; } } + else if (rcode.is_fn_code () + && gimple_call_builtin_p (stmt, rcode)) + { + unsigned i; + for (i = 0; i < gimple_call_num_args (stmt); ++i) + { + gcc_assert (ops[i] != NULL_TREE); + gimple_call_set_arg (stmt, i, ops[i]); + } + if (i < 3) + gcc_assert (ops[i] == NULL_TREE); + return true; + } else if (!inplace) { if (gimple_has_lhs (stmt)) Index: gcc/gimple-match-head.c =================================================================== *** gcc/gimple-match-head.c (revision 226086) --- gcc/gimple-match-head.c (working copy) *************** maybe_push_res_to_seq (code_helper rcode *** 337,355 **** tree decl = builtin_decl_implicit (rcode); if (!decl) return NULL_TREE; - unsigned nargs = type_num_arguments (TREE_TYPE (decl)); - gcc_assert (nargs <= 3); /* Play safe and do not allow abnormals to be mentioned in newly created statements. */ ! if ((TREE_CODE (ops[0]) == SSA_NAME ! && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0])) ! || (nargs >= 2 ! && TREE_CODE (ops[1]) == SSA_NAME ! && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1])) ! || (nargs == 3 ! && TREE_CODE (ops[2]) == SSA_NAME ! && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2]))) ! return NULL_TREE; if (!res) res = make_ssa_name (type); gimple new_stmt = gimple_build_call (decl, nargs, ops[0], ops[1], ops[2]); --- 337,354 ---- tree decl = builtin_decl_implicit (rcode); if (!decl) return NULL_TREE; /* Play safe and do not allow abnormals to be mentioned in newly created statements. */ ! unsigned nargs; ! for (nargs = 0; nargs < 3; ++nargs) ! { ! if (!ops[nargs]) ! break; ! if (TREE_CODE (ops[nargs]) == SSA_NAME ! && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[nargs])) ! return NULL_TREE; ! } ! gcc_assert (nargs != 0); if (!res) res = make_ssa_name (type); gimple new_stmt = gimple_build_call (decl, nargs, ops[0], ops[1], ops[2]); *************** gimple_simplify (enum built_in_function *** 562,567 **** --- 561,583 ---- return maybe_push_res_to_seq (rcode, type, ops, seq); } + /* Helper for gimple_simplify valueizing OP using VALUEIZE and setting + VALUEIZED to true if valueization changed OP. */ + + static inline tree + do_valueize (tree op, tree (*valueize)(tree), bool &valueized) + { + if (valueize && TREE_CODE (op) == SSA_NAME) + { + tree tem = valueize (op); + if (tem && tem != op) + { + op = tem; + valueized = true; + } + } + return op; + } /* The main STMT based simplification entry. It is used by the fold_stmt and the fold_stmt_to_constant APIs. */ *************** gimple_simplify (gimple stmt, *** 586,616 **** || code == VIEW_CONVERT_EXPR) { tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); ! if (top_valueize && TREE_CODE (op0) == SSA_NAME) ! { ! tree tem = top_valueize (op0); ! if (tem) ! op0 = tem; ! } *rcode = code; ops[0] = op0; ! return gimple_resimplify1 (seq, rcode, type, ops, valueize); } else if (code == BIT_FIELD_REF) { tree rhs1 = gimple_assign_rhs1 (stmt); tree op0 = TREE_OPERAND (rhs1, 0); ! if (top_valueize && TREE_CODE (op0) == SSA_NAME) ! { ! tree tem = top_valueize (op0); ! if (tem) ! op0 = tem; ! } *rcode = code; ops[0] = op0; ops[1] = TREE_OPERAND (rhs1, 1); ops[2] = TREE_OPERAND (rhs1, 2); ! return gimple_resimplify3 (seq, rcode, type, ops, valueize); } else if (code == SSA_NAME && top_valueize) --- 602,626 ---- || code == VIEW_CONVERT_EXPR) { tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); ! bool valueized = false; ! op0 = do_valueize (op0, top_valueize, valueized); *rcode = code; ops[0] = op0; ! return (gimple_resimplify1 (seq, rcode, type, ops, valueize) ! || valueized); } else if (code == BIT_FIELD_REF) { tree rhs1 = gimple_assign_rhs1 (stmt); tree op0 = TREE_OPERAND (rhs1, 0); ! bool valueized = false; ! op0 = do_valueize (op0, top_valueize, valueized); *rcode = code; ops[0] = op0; ops[1] = TREE_OPERAND (rhs1, 1); ops[2] = TREE_OPERAND (rhs1, 2); ! return (gimple_resimplify3 (seq, rcode, type, ops, valueize) ! || valueized); } else if (code == SSA_NAME && top_valueize) *************** gimple_simplify (gimple stmt, *** 627,691 **** case GIMPLE_UNARY_RHS: { tree rhs1 = gimple_assign_rhs1 (stmt); ! if (top_valueize && TREE_CODE (rhs1) == SSA_NAME) ! { ! tree tem = top_valueize (rhs1); ! if (tem) ! rhs1 = tem; ! } *rcode = code; ops[0] = rhs1; ! return gimple_resimplify1 (seq, rcode, type, ops, valueize); } case GIMPLE_BINARY_RHS: { tree rhs1 = gimple_assign_rhs1 (stmt); - if (top_valueize && TREE_CODE (rhs1) == SSA_NAME) - { - tree tem = top_valueize (rhs1); - if (tem) - rhs1 = tem; - } tree rhs2 = gimple_assign_rhs2 (stmt); ! if (top_valueize && TREE_CODE (rhs2) == SSA_NAME) ! { ! tree tem = top_valueize (rhs2); ! if (tem) ! rhs2 = tem; ! } *rcode = code; ops[0] = rhs1; ops[1] = rhs2; ! return gimple_resimplify2 (seq, rcode, type, ops, valueize); } case GIMPLE_TERNARY_RHS: { tree rhs1 = gimple_assign_rhs1 (stmt); - if (top_valueize && TREE_CODE (rhs1) == SSA_NAME) - { - tree tem = top_valueize (rhs1); - if (tem) - rhs1 = tem; - } tree rhs2 = gimple_assign_rhs2 (stmt); - if (top_valueize && TREE_CODE (rhs2) == SSA_NAME) - { - tree tem = top_valueize (rhs2); - if (tem) - rhs2 = tem; - } tree rhs3 = gimple_assign_rhs3 (stmt); ! if (top_valueize && TREE_CODE (rhs3) == SSA_NAME) ! { ! tree tem = top_valueize (rhs3); ! if (tem) ! rhs3 = tem; ! } *rcode = code; ops[0] = rhs1; ops[1] = rhs2; ops[2] = rhs3; ! return gimple_resimplify3 (seq, rcode, type, ops, valueize); } default: gcc_unreachable (); --- 637,677 ---- case GIMPLE_UNARY_RHS: { tree rhs1 = gimple_assign_rhs1 (stmt); ! bool valueized = false; ! rhs1 = do_valueize (rhs1, top_valueize, valueized); *rcode = code; ops[0] = rhs1; ! return (gimple_resimplify1 (seq, rcode, type, ops, valueize) ! || valueized); } case GIMPLE_BINARY_RHS: { tree rhs1 = gimple_assign_rhs1 (stmt); tree rhs2 = gimple_assign_rhs2 (stmt); ! bool valueized = false; ! rhs1 = do_valueize (rhs1, top_valueize, valueized); ! rhs2 = do_valueize (rhs2, top_valueize, valueized); *rcode = code; ops[0] = rhs1; ops[1] = rhs2; ! return (gimple_resimplify2 (seq, rcode, type, ops, valueize) ! || valueized); } case GIMPLE_TERNARY_RHS: { tree rhs1 = gimple_assign_rhs1 (stmt); tree rhs2 = gimple_assign_rhs2 (stmt); tree rhs3 = gimple_assign_rhs3 (stmt); ! bool valueized = false; ! rhs1 = do_valueize (rhs1, top_valueize, valueized); ! rhs2 = do_valueize (rhs2, top_valueize, valueized); ! rhs3 = do_valueize (rhs3, top_valueize, valueized); *rcode = code; ops[0] = rhs1; ops[1] = rhs2; ops[2] = rhs3; ! return (gimple_resimplify3 (seq, rcode, type, ops, valueize) ! || valueized); } default: gcc_unreachable (); *************** gimple_simplify (gimple stmt, *** 695,790 **** case GIMPLE_CALL: /* ??? This way we can't simplify calls with side-effects. */ ! if (gimple_call_lhs (stmt) != NULL_TREE) { tree fn = gimple_call_fn (stmt); /* ??? Internal function support missing. */ if (!fn) return false; ! if (top_valueize && TREE_CODE (fn) == SSA_NAME) ! { ! tree tem = top_valueize (fn); ! if (tem) ! fn = tem; ! } ! if (!fn ! || TREE_CODE (fn) != ADDR_EXPR ! || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL ! || DECL_BUILT_IN_CLASS (TREE_OPERAND (fn, 0)) != BUILT_IN_NORMAL ! || !builtin_decl_implicit (DECL_FUNCTION_CODE (TREE_OPERAND (fn, 0))) ! || !gimple_builtin_call_types_compatible_p (stmt, ! TREE_OPERAND (fn, 0))) return false; tree decl = TREE_OPERAND (fn, 0); tree type = TREE_TYPE (gimple_call_lhs (stmt)); switch (gimple_call_num_args (stmt)) { case 1: ! { ! tree arg1 = gimple_call_arg (stmt, 0); ! if (top_valueize && TREE_CODE (arg1) == SSA_NAME) ! { ! tree tem = top_valueize (arg1); ! if (tem) ! arg1 = tem; ! } ! *rcode = DECL_FUNCTION_CODE (decl); ! ops[0] = arg1; ! return gimple_resimplify1 (seq, rcode, type, ops, valueize); ! } case 2: ! { ! tree arg1 = gimple_call_arg (stmt, 0); ! if (top_valueize && TREE_CODE (arg1) == SSA_NAME) ! { ! tree tem = top_valueize (arg1); ! if (tem) ! arg1 = tem; ! } ! tree arg2 = gimple_call_arg (stmt, 1); ! if (top_valueize && TREE_CODE (arg2) == SSA_NAME) ! { ! tree tem = top_valueize (arg2); ! if (tem) ! arg2 = tem; ! } ! *rcode = DECL_FUNCTION_CODE (decl); ! ops[0] = arg1; ! ops[1] = arg2; ! return gimple_resimplify2 (seq, rcode, type, ops, valueize); ! } case 3: ! { ! tree arg1 = gimple_call_arg (stmt, 0); ! if (top_valueize && TREE_CODE (arg1) == SSA_NAME) ! { ! tree tem = top_valueize (arg1); ! if (tem) ! arg1 = tem; ! } ! tree arg2 = gimple_call_arg (stmt, 1); ! if (top_valueize && TREE_CODE (arg2) == SSA_NAME) ! { ! tree tem = top_valueize (arg2); ! if (tem) ! arg2 = tem; ! } ! tree arg3 = gimple_call_arg (stmt, 2); ! if (top_valueize && TREE_CODE (arg3) == SSA_NAME) ! { ! tree tem = top_valueize (arg3); ! if (tem) ! arg3 = tem; ! } ! *rcode = DECL_FUNCTION_CODE (decl); ! ops[0] = arg1; ! ops[1] = arg2; ! ops[2] = arg3; ! return gimple_resimplify3 (seq, rcode, type, ops, valueize); ! } default: ! return false; } } break; --- 681,726 ---- case GIMPLE_CALL: /* ??? This way we can't simplify calls with side-effects. */ ! if (gimple_call_lhs (stmt) != NULL_TREE ! && gimple_call_num_args (stmt) >= 1 ! && gimple_call_num_args (stmt) <= 3) { tree fn = gimple_call_fn (stmt); /* ??? Internal function support missing. */ if (!fn) return false; ! bool valueized = false; ! fn = do_valueize (fn, top_valueize, valueized); ! if (TREE_CODE (fn) != ADDR_EXPR ! || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL) return false; tree decl = TREE_OPERAND (fn, 0); + if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL + || !builtin_decl_implicit (DECL_FUNCTION_CODE (decl)) + || !gimple_builtin_call_types_compatible_p (stmt, decl)) + return false; + tree type = TREE_TYPE (gimple_call_lhs (stmt)); + *rcode = DECL_FUNCTION_CODE (decl); + for (unsigned i = 0; i < gimple_call_num_args (stmt); ++i) + { + tree arg = gimple_call_arg (stmt, i); + ops[i] = do_valueize (arg, top_valueize, valueized); + } switch (gimple_call_num_args (stmt)) { case 1: ! return (gimple_resimplify1 (seq, rcode, type, ops, valueize) ! || valueized); case 2: ! return (gimple_resimplify2 (seq, rcode, type, ops, valueize) ! || valueized); case 3: ! return (gimple_resimplify3 (seq, rcode, type, ops, valueize) ! || valueized); default: ! gcc_unreachable (); } } break; *************** gimple_simplify (gimple stmt, *** 792,814 **** case GIMPLE_COND: { tree lhs = gimple_cond_lhs (stmt); - if (top_valueize && TREE_CODE (lhs) == SSA_NAME) - { - tree tem = top_valueize (lhs); - if (tem) - lhs = tem; - } tree rhs = gimple_cond_rhs (stmt); ! if (top_valueize && TREE_CODE (rhs) == SSA_NAME) ! { ! tree tem = top_valueize (rhs); ! if (tem) ! rhs = tem; ! } *rcode = gimple_cond_code (stmt); ops[0] = lhs; ops[1] = rhs; ! return gimple_resimplify2 (seq, rcode, boolean_type_node, ops, valueize); } default: --- 728,743 ---- case GIMPLE_COND: { tree lhs = gimple_cond_lhs (stmt); tree rhs = gimple_cond_rhs (stmt); ! bool valueized = false; ! lhs = do_valueize (lhs, top_valueize, valueized); ! rhs = do_valueize (rhs, top_valueize, valueized); *rcode = gimple_cond_code (stmt); ops[0] = lhs; ops[1] = rhs; ! return (gimple_resimplify2 (seq, rcode, ! boolean_type_node, ops, valueize) ! || valueized); } default: