To get desired transforms from tree-ssa-forwprop.c which uses fold_stmt. Bootstrapped and tested on x86_64-unknown-linux-gnu, applied.
Richard. 2014-09-15 Richard Biener <rguent...@suse.de> * gimple-fold.c: Include tree-eh.c. (fold_stmt_1): Handle GIMPLE_CONDs for gimple_simplify. * gimple-match-head.c (gimple_simplify): Likewise. * match-comparison.pd (bool != 0): Avoid some churn on GIMPLE and amend comment. Index: gcc/gimple-fold.c =================================================================== --- gcc/gimple-fold.c (revision 215212) +++ gcc/gimple-fold.c (working copy) @@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. #include "dbgcnt.h" #include "builtins.h" #include "output.h" +#include "tree-eh.h" #include "gimple-match.h" @@ -2881,15 +2882,67 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, no further stmts need to be inserted (basically disallow creating of new SSA names). */ if (!inplace - || is_gimple_assign (stmt)) + || is_gimple_assign (stmt) + || gimple_code (stmt) == GIMPLE_COND) { gimple_seq seq = NULL; code_helper rcode; tree ops[3] = {}; if (gimple_simplify (stmt, &rcode, ops, inplace ? NULL : &seq, valueize)) { - if (is_gimple_assign (stmt) - && rcode.is_tree_code ()) + if (gimple_code (stmt) == GIMPLE_COND) + { + gcc_assert (rcode.is_tree_code ()); + if (TREE_CODE_CLASS ((enum tree_code)rcode) == tcc_comparison + /* GIMPLE_CONDs condition may not throw. */ + /* ??? Not sure how we want to deal with combining + from possibly throwing statements. Trivial + simplifications may lead to DCEing an internal + throw. But we probably still want to simplify + things to a constant for example? Similar to + abnormals we could discard the simplification + result if we ever push a could-throw stmt to + the sequence. */ + && (!flag_exceptions + || !cfun->can_throw_non_call_exceptions + || !operation_could_trap_p (rcode, FLOAT_TYPE_P (TREE_TYPE (ops[0])), false, NULL_TREE))) + gimple_cond_set_condition (stmt, rcode, ops[0], ops[1]); + else if (rcode == SSA_NAME) + gimple_cond_set_condition (stmt, NE_EXPR, ops[0], + build_zero_cst (TREE_TYPE (ops[0]))); + else if (rcode == INTEGER_CST) + { + if (integer_zerop (ops[0])) + gimple_cond_make_false (stmt); + else + gimple_cond_make_true (stmt); + } + else if (!inplace) + { + tree res = maybe_push_res_to_seq (rcode, boolean_type_node, + ops, &seq); + if (!res) + goto fail; + gimple_cond_set_condition (stmt, NE_EXPR, res, + build_zero_cst (TREE_TYPE (res))); + } + else + goto fail; + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "gimple_simplified to "); + if (!gimple_seq_empty_p (seq)) + print_gimple_seq (dump_file, seq, 0, TDF_SLIM); + print_gimple_stmt (dump_file, gsi_stmt (*gsi), + 0, TDF_SLIM); + } + gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT); + changed = true; +fail: + ; + } + else if (is_gimple_assign (stmt) + && rcode.is_tree_code ()) { if ((!inplace || gimple_num_ops (stmt) <= get_gimple_rhs_num_ops (rcode)) Index: gcc/gimple-match-head.c =================================================================== --- gcc/gimple-match-head.c (revision 215212) +++ gcc/gimple-match-head.c (working copy) @@ -573,213 +573,244 @@ gimple_simplify (gimple stmt, code_helper *rcode, tree *ops, gimple_seq *seq, tree (*valueize)(tree)) { - if (is_gimple_assign (stmt)) + switch (gimple_code (stmt)) { - enum tree_code code = gimple_assign_rhs_code (stmt); - tree type = TREE_TYPE (gimple_assign_lhs (stmt)); - switch (gimple_assign_rhs_class (stmt)) - { - case GIMPLE_SINGLE_RHS: - if (code == REALPART_EXPR - || code == IMAGPART_EXPR - || code == VIEW_CONVERT_EXPR) + case GIMPLE_ASSIGN: + { + enum tree_code code = gimple_assign_rhs_code (stmt); + tree type = TREE_TYPE (gimple_assign_lhs (stmt)); + switch (gimple_assign_rhs_class (stmt)) + { + case GIMPLE_SINGLE_RHS: + if (code == REALPART_EXPR + || code == IMAGPART_EXPR + || code == VIEW_CONVERT_EXPR) + { + tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); + if (valueize && TREE_CODE (op0) == SSA_NAME) + { + op0 = valueize (op0); + if (!op0) + return false; + } + *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 (valueize && TREE_CODE (op0) == SSA_NAME) + { + op0 = valueize (op0); + if (!op0) + return false; + } + *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 + && valueize) + { + tree op0 = gimple_assign_rhs1 (stmt); + tree valueized = valueize (op0); + if (!valueized || op0 == valueized) + return false; + ops[0] = valueized; + *rcode = TREE_CODE (op0); + return true; + } + break; + case GIMPLE_UNARY_RHS: { - tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); - if (valueize && TREE_CODE (op0) == SSA_NAME) + tree rhs1 = gimple_assign_rhs1 (stmt); + if (valueize && TREE_CODE (rhs1) == SSA_NAME) { - op0 = valueize (op0); - if (!op0) + rhs1 = valueize (rhs1); + if (!rhs1) return false; } *rcode = code; - ops[0] = op0; + ops[0] = rhs1; return gimple_resimplify1 (seq, rcode, type, ops, valueize); } - else if (code == BIT_FIELD_REF) + case GIMPLE_BINARY_RHS: { tree rhs1 = gimple_assign_rhs1 (stmt); - tree op0 = TREE_OPERAND (rhs1, 0); - if (valueize && TREE_CODE (op0) == SSA_NAME) + if (valueize && TREE_CODE (rhs1) == SSA_NAME) { - op0 = valueize (op0); - if (!op0) + rhs1 = valueize (rhs1); + if (!rhs1) + return false; + } + tree rhs2 = gimple_assign_rhs2 (stmt); + if (valueize && TREE_CODE (rhs2) == SSA_NAME) + { + rhs2 = valueize (rhs2); + if (!rhs2) return false; } *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); + ops[0] = rhs1; + ops[1] = rhs2; + return gimple_resimplify2 (seq, rcode, type, ops, valueize); } - else if (code == SSA_NAME - && valueize) + case GIMPLE_TERNARY_RHS: { - tree op0 = gimple_assign_rhs1 (stmt); - tree valueized = valueize (op0); - if (!valueized || op0 == valueized) - return false; - ops[0] = valueized; - *rcode = TREE_CODE (op0); - return true; + tree rhs1 = gimple_assign_rhs1 (stmt); + if (valueize && TREE_CODE (rhs1) == SSA_NAME) + { + rhs1 = valueize (rhs1); + if (!rhs1) + return false; + } + tree rhs2 = gimple_assign_rhs2 (stmt); + if (valueize && TREE_CODE (rhs2) == SSA_NAME) + { + rhs2 = valueize (rhs2); + if (!rhs2) + return false; + } + tree rhs3 = gimple_assign_rhs3 (stmt); + if (valueize && TREE_CODE (rhs3) == SSA_NAME) + { + rhs3 = valueize (rhs3); + if (!rhs3) + return false; + } + *rcode = code; + ops[0] = rhs1; + ops[1] = rhs2; + ops[2] = rhs3; + return gimple_resimplify3 (seq, rcode, type, ops, valueize); } - break; - case GIMPLE_UNARY_RHS: - { - tree rhs1 = gimple_assign_rhs1 (stmt); - if (valueize && TREE_CODE (rhs1) == SSA_NAME) - { - rhs1 = valueize (rhs1); - if (!rhs1) - return false; - } - *rcode = code; - ops[0] = rhs1; - return gimple_resimplify1 (seq, rcode, type, ops, valueize); - } - case GIMPLE_BINARY_RHS: - { - tree rhs1 = gimple_assign_rhs1 (stmt); - if (valueize && TREE_CODE (rhs1) == SSA_NAME) - { - rhs1 = valueize (rhs1); - if (!rhs1) - return false; - } - tree rhs2 = gimple_assign_rhs2 (stmt); - if (valueize && TREE_CODE (rhs2) == SSA_NAME) - { - rhs2 = valueize (rhs2); - if (!rhs2) - return false; - } - *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 (valueize && TREE_CODE (rhs1) == SSA_NAME) - { - rhs1 = valueize (rhs1); - if (!rhs1) - return false; - } - tree rhs2 = gimple_assign_rhs2 (stmt); - if (valueize && TREE_CODE (rhs2) == SSA_NAME) - { - rhs2 = valueize (rhs2); - if (!rhs2) - return false; - } - tree rhs3 = gimple_assign_rhs3 (stmt); - if (valueize && TREE_CODE (rhs3) == SSA_NAME) - { - rhs3 = valueize (rhs3); - if (!rhs3) - return false; - } - *rcode = code; - ops[0] = rhs1; - ops[1] = rhs2; - ops[2] = rhs3; - return gimple_resimplify3 (seq, rcode, type, ops, valueize); + default: + gcc_unreachable (); } - default: - gcc_unreachable (); - } - } - else if (is_gimple_call (stmt) - /* ??? This way we can't simplify calls with side-effects. */ - && gimple_call_lhs (stmt) != NULL_TREE) - { - tree fn = gimple_call_fn (stmt); - /* ??? Internal function support missing. */ - if (!fn) - return false; - if (TREE_CODE (fn) == SSA_NAME - && valueize) - fn = valueize (fn); - 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; + break; + } - tree decl = TREE_OPERAND (fn, 0); - tree type = TREE_TYPE (gimple_call_lhs (stmt)); - switch (gimple_call_num_args (stmt)) + case GIMPLE_CALL: + /* ??? This way we can't simplify calls with side-effects. */ + if (gimple_call_lhs (stmt) != NULL_TREE) { - case 1: - { - tree arg1 = gimple_call_arg (stmt, 0); - if (valueize && TREE_CODE (arg1) == SSA_NAME) - { - arg1 = valueize (arg1); - if (!arg1) - return false; - } - *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 (valueize && TREE_CODE (arg1) == SSA_NAME) - { - arg1 = valueize (arg1); - if (!arg1) - return false; - } - tree arg2 = gimple_call_arg (stmt, 1); - if (valueize && TREE_CODE (arg2) == SSA_NAME) - { - arg2 = valueize (arg2); - if (!arg2) - return false; - } - *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 (valueize && TREE_CODE (arg1) == SSA_NAME) - { - arg1 = valueize (arg1); - if (!arg1) - return false; - } - tree arg2 = gimple_call_arg (stmt, 1); - if (valueize && TREE_CODE (arg2) == SSA_NAME) - { - arg2 = valueize (arg2); - if (!arg2) - return false; - } - tree arg3 = gimple_call_arg (stmt, 2); - if (valueize && TREE_CODE (arg3) == SSA_NAME) + tree fn = gimple_call_fn (stmt); + /* ??? Internal function support missing. */ + if (!fn) + return false; + if (TREE_CODE (fn) == SSA_NAME + && valueize) + fn = valueize (fn); + 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: { - arg3 = valueize (arg3); - if (!arg3) - return false; + tree arg1 = gimple_call_arg (stmt, 0); + if (valueize && TREE_CODE (arg1) == SSA_NAME) + { + arg1 = valueize (arg1); + if (!arg1) + return false; + } + *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 (valueize && TREE_CODE (arg1) == SSA_NAME) + { + arg1 = valueize (arg1); + if (!arg1) + return false; + } + tree arg2 = gimple_call_arg (stmt, 1); + if (valueize && TREE_CODE (arg2) == SSA_NAME) + { + arg2 = valueize (arg2); + if (!arg2) + return false; + } + *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 (valueize && TREE_CODE (arg1) == SSA_NAME) + { + arg1 = valueize (arg1); + if (!arg1) + return false; + } + tree arg2 = gimple_call_arg (stmt, 1); + if (valueize && TREE_CODE (arg2) == SSA_NAME) + { + arg2 = valueize (arg2); + if (!arg2) + return false; + } + tree arg3 = gimple_call_arg (stmt, 2); + if (valueize && TREE_CODE (arg3) == SSA_NAME) + { + arg3 = valueize (arg3); + if (!arg3) + return false; + } + *rcode = DECL_FUNCTION_CODE (decl); + ops[0] = arg1; + ops[1] = arg2; + ops[2] = arg3; + return gimple_resimplify3 (seq, rcode, type, ops, valueize); } - *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; + default: + return false; + } } + break; + + case GIMPLE_COND: + { + tree lhs = gimple_cond_lhs (stmt); + if (valueize && TREE_CODE (lhs) == SSA_NAME) + { + lhs = valueize (lhs); + if (!lhs) + return false; + } + tree rhs = gimple_cond_rhs (stmt); + if (valueize && TREE_CODE (rhs) == SSA_NAME) + { + rhs = valueize (rhs); + if (!rhs) + return false; + } + *rcode = gimple_cond_code (stmt); + ops[0] = lhs; + ops[1] = rhs; + return gimple_resimplify2 (seq, rcode, boolean_type_node, ops, valueize); + } + + default: + break; } return false; Index: gcc/match-comparison.pd =================================================================== --- gcc/match-comparison.pd (revision 215212) +++ gcc/match-comparison.pd (working copy) @@ -1,10 +1,18 @@ /* From fold_binary. */ +/* On GIMPLE bool != 0 is simply the canonical way to express a + condition in COND_EXPRs and GIMPLE_CONDs. + ??? Of course for assignments we still may want to strip those... */ (simplify (ne @0 integer_zerop@1) (if (TREE_CODE (TREE_TYPE (@0)) == BOOLEAN_TYPE) - /* ??? In GENERIC the type of the comparison may be 'int'. */ - (convert @0))) + /* On GENERIC comparisons can have arbitrary integer types. */ + (if (GENERIC) + (convert @0)) + /* On GIMPLE boolean types may have a precision != 1 thus the + comparison serves as a more canonical required conversion. */ + (if (GIMPLE && useless_type_conversion_p (type, TREE_TYPE (@0))) + @0))) /* Distribute operations in equality compares. */ (for op (eq ne)