On Wed, Apr 27, 2016 at 7:34 AM, Marc Glisse <marc.gli...@inria.fr> wrote: > Here is the current patch (passed regtest), after moving defer/undefer from > forwprop to fold_stmt_1. I am not sure if checking no_warning at the end of > fold_stmt_1 is safe, or if I should save its value at the beginning of the > function, in case some of the transformations clear it.
I think you need to check it on the original stmt, it is preserved only if we re-use the old stmt memory. > > On Tue, 26 Apr 2016, Marc Glisse wrote: > >> On Tue, 26 Apr 2016, Richard Biener wrote: >> >>> On Sun, Apr 24, 2016 at 7:14 PM, Marc Glisse <marc.gli...@inria.fr> >>> wrote: >>>> >>>> Hello, >>>> >>>> trying to move a first pattern from fold_comparison. >>>> >>>> I first tried without single_use. It brought the number of 'free' in >>>> g++.dg/tree-ssa/pr61034.C down to 11, changed gcc.dg/sms-6.c to only 2 >>>> SMS >>>> (I don't think the generated code was worse, maybe even better, but I >>>> don't >>>> know ppc asm), broke Wstrict-overflow-18.c (the optimization moved from >>>> VRP >>>> to CCP if I remember correctly), and caused IVOPTS to make a mess in >>>> guality/pr54693-2.c (much longer code, and many <optimized> debug >>>> variables). If someone wants to drop the single_use, they can work on >>>> that >>>> after this patch is in. >>>> >>>> The conditions do not exactly match the ones in fold-const.c, but I >>>> guess >>>> they are close. The warning in the constant case was missing in >>>> fold_comparison, but present in VRP, so I had to add it not to regress. >>>> >>>> I don't think we were warning much from match.pd. I can't say that I am >>>> a >>>> big fan of those strict overflow warnings, but I expect people would >>>> complain if we just dropped the existing ones when moving the transforms >>>> to >>>> match.pd? >>> >>> >>> I just dropped them for patterns I moved (luckily we didn't have >>> testcases sofar ;)) >>> >>> If we really want to warn from match.pd then you should do the >>> defer/undefer >>> stuff in fold_stmt itself (same condition I guess) and defer/undefer >>> without >>> warning in gimple_fold_stmt_to_constant_1. >> >> >> Moving it to fold_stmt_1 seems like a good idea, much better than putting >> it in forwprop. Looking at gimple_fold_stmt_to_constant_1 on the other hand, >> I have some concerns. If we do not warn for gimple_fold_stmt_to_constant_1, >> we are going to miss some warnings (I believe there is at least one testcase >> that will break, where VRP currently warns but CCP will come first). On the >> other hand, gimple_fold_stmt_to_constant_1 doesn't do much validation on its >> return value, each caller has their own idea of which results are >> acceptable, so it is only in the (many) callers that we can defer/undefer, >> or we might warn for transformations that we don't actually perform. CCP >> already has the defer/undefer calls around ccp_fold and thus >> gimple_fold_stmt_to_constant_1. >> >>> So you actually ran into a testcase that expected the warning? >> >> >> Several of them if I remember correctly... >> >>>> I wanted to restrict the equality case to TYPE_OVERFLOW_WRAPS || >>>> TYPE_OVERFLOW_UNDEFINED, but that broke 20041114-1.c at -O1 (no strict >>>> overflow), so I went with some kind of complement we use elsewhere. >>> >>> >>> I think I prefer to move things 1:1 (unless sth regresses) and fix bugs >>> in the >>> fold-const.c variant as followup (possibly also adding testcases). >> >> >> Well, yes, but things do indeed regress quite regularly when moving things >> 1:1 :-( At least unless we add a big (if (GENERIC) ...) around the >> transformation. >> >>> IMHO -fno-strict-overflow needs to go. It has very wary designed >>> semantics >>> (ops neither wrap nor have undefined overflow). >> >> >> Maybe make it an alias for -fwrapv? > > > -- > Marc Glisse > > Index: trunk4/gcc/fold-const.c > =================================================================== > --- trunk4/gcc/fold-const.c (revision 235452) > +++ trunk4/gcc/fold-const.c (working copy) > @@ -290,21 +290,21 @@ fold_undefer_and_ignore_overflow_warning > > bool > fold_deferring_overflow_warnings_p (void) > { > return fold_deferring_overflow_warnings > 0; > } > > /* This is called when we fold something based on the fact that signed > overflow is undefined. */ > > -static void > +void > fold_overflow_warning (const char* gmsgid, enum warn_strict_overflow_code > wc) > { > if (fold_deferring_overflow_warnings > 0) > { > if (fold_deferred_overflow_warning == NULL > || wc < fold_deferred_overflow_code) > { > fold_deferred_overflow_warning = gmsgid; > fold_deferred_overflow_code = wc; > } > @@ -8366,89 +8366,20 @@ fold_comparison (location_t loc, enum tr > { > const bool equality_code = (code == EQ_EXPR || code == NE_EXPR); > tree arg0, arg1, tem; > > arg0 = op0; > arg1 = op1; > > STRIP_SIGN_NOPS (arg0); > STRIP_SIGN_NOPS (arg1); > > - /* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 -+ C1. > */ > - if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR) > - && (equality_code > - || (ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg0)) > - && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0)))) > - && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST > - && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1)) > - && TREE_CODE (arg1) == INTEGER_CST > - && !TREE_OVERFLOW (arg1)) > - { > - const enum tree_code > - reverse_op = TREE_CODE (arg0) == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR; > - tree const1 = TREE_OPERAND (arg0, 1); > - tree const2 = fold_convert_loc (loc, TREE_TYPE (const1), arg1); > - tree variable = TREE_OPERAND (arg0, 0); > - tree new_const = int_const_binop (reverse_op, const2, const1); > - > - /* If the constant operation overflowed this can be > - simplified as a comparison against INT_MAX/INT_MIN. */ > - if (TREE_OVERFLOW (new_const) > - && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0))) > - { > - int const1_sgn = tree_int_cst_sgn (const1); > - enum tree_code code2 = code; > - > - /* Get the sign of the constant on the lhs if the > - operation were VARIABLE + CONST1. */ > - if (TREE_CODE (arg0) == MINUS_EXPR) > - const1_sgn = -const1_sgn; > - > - /* The sign of the constant determines if we overflowed > - INT_MAX (const1_sgn == -1) or INT_MIN (const1_sgn == 1). > - Canonicalize to the INT_MIN overflow by swapping the comparison > - if necessary. */ > - if (const1_sgn == -1) > - code2 = swap_tree_comparison (code); > - > - /* We now can look at the canonicalized case > - VARIABLE + 1 CODE2 INT_MIN > - and decide on the result. */ > - switch (code2) > - { > - case EQ_EXPR: > - case LT_EXPR: > - case LE_EXPR: > - return > - omit_one_operand_loc (loc, type, boolean_false_node, > variable); > - > - case NE_EXPR: > - case GE_EXPR: > - case GT_EXPR: > - return > - omit_one_operand_loc (loc, type, boolean_true_node, > variable); > - > - default: > - gcc_unreachable (); > - } > - } > - else > - { > - if (!equality_code) > - fold_overflow_warning ("assuming signed overflow does not occur > " > - "when changing X +- C1 cmp C2 to " > - "X cmp C2 -+ C1", > - WARN_STRICT_OVERFLOW_COMPARISON); > - return fold_build2_loc (loc, code, type, variable, new_const); > - } > - } > - > /* For comparisons of pointers we can decompose it to a compile time > comparison of the base objects and the offsets into the object. > This requires at least one operand being an ADDR_EXPR or a > POINTER_PLUS_EXPR to do more than the operand_equal_p test below. */ > if (POINTER_TYPE_P (TREE_TYPE (arg0)) > && (TREE_CODE (arg0) == ADDR_EXPR > || TREE_CODE (arg1) == ADDR_EXPR > || TREE_CODE (arg0) == POINTER_PLUS_EXPR > || TREE_CODE (arg1) == POINTER_PLUS_EXPR)) > { > Index: trunk4/gcc/fold-const.h > =================================================================== > --- trunk4/gcc/fold-const.h (revision 235452) > +++ trunk4/gcc/fold-const.h (working copy) > @@ -13,20 +13,22 @@ WARRANTY; without even the implied warra > FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > for more details. > > You should have received a copy of the GNU General Public License > along with GCC; see the file COPYING3. If not see > <http://www.gnu.org/licenses/>. */ > > #ifndef GCC_FOLD_CONST_H > #define GCC_FOLD_CONST_H > > +#include <flag-types.h> > + I think the canonical way is to include options.h where you include fold-const.h ... (ick) Doesn't the prototype serve as a forward declaration only and thus including options.h from gimple-match-head.c is enough? Otherwise the patch looks ok to me. Thanks, Richard. > /* Non-zero if we are folding constants inside an initializer; zero > otherwise. */ > extern int folding_initializer; > > /* Convert between trees and native memory representation. */ > extern int native_encode_expr (const_tree, unsigned char *, int, int off = > -1); > extern tree native_interpret_expr (tree, const unsigned char *, int); > > /* Fold constants as much as possible in an expression. > Returns the simplified expression. > @@ -79,20 +81,21 @@ extern bool fold_convertible_p (const_tr > fold_convert_loc (UNKNOWN_LOCATION, T1, T2) > extern tree fold_convert_loc (location_t, tree, tree); > extern tree fold_single_bit_test (location_t, enum tree_code, tree, tree, > tree); > extern tree fold_ignored_result (tree); > extern tree fold_abs_const (tree, tree); > extern tree fold_indirect_ref_1 (location_t, tree, tree); > extern void fold_defer_overflow_warnings (void); > extern void fold_undefer_overflow_warnings (bool, const gimple *, int); > extern void fold_undefer_and_ignore_overflow_warnings (void); > extern bool fold_deferring_overflow_warnings_p (void); > +extern void fold_overflow_warning (const char*, enum > warn_strict_overflow_code); > extern int operand_equal_p (const_tree, const_tree, unsigned int); > extern int multiple_of_p (tree, const_tree, const_tree); > #define omit_one_operand(T1,T2,T3)\ > omit_one_operand_loc (UNKNOWN_LOCATION, T1, T2, T3) > extern tree omit_one_operand_loc (location_t, tree, tree, tree); > #define omit_two_operands(T1,T2,T3,T4)\ > omit_two_operands_loc (UNKNOWN_LOCATION, T1, T2, T3, T4) > extern tree omit_two_operands_loc (location_t, tree, tree, tree, tree); > #define invert_truthvalue(T)\ > invert_truthvalue_loc (UNKNOWN_LOCATION, T) > Index: trunk4/gcc/gimple-fold.c > =================================================================== > --- trunk4/gcc/gimple-fold.c (revision 235452) > +++ trunk4/gcc/gimple-fold.c (working copy) > @@ -3519,20 +3519,21 @@ maybe_canonicalize_mem_ref_addr (tree *t > > /* Worker for both fold_stmt and fold_stmt_inplace. The INPLACE argument > distinguishes both cases. */ > > static bool > fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, tree (*valueize) > (tree)) > { > bool changed = false; > gimple *stmt = gsi_stmt (*gsi); > unsigned i; > + fold_defer_overflow_warnings (); > > /* First do required canonicalization of [TARGET_]MEM_REF addresses > after propagation. > ??? This shouldn't be done in generic folding but in the > propagation helpers which also know whether an address was > propagated. > Also canonicalize operand order. */ > switch (gimple_code (stmt)) > { > case GIMPLE_ASSIGN: > @@ -3811,20 +3812,22 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, > { > tree new_lhs = maybe_fold_reference (lhs, true); > if (new_lhs) > { > gimple_set_lhs (stmt, new_lhs); > changed = true; > } > } > } > > + fold_undefer_overflow_warnings (changed && !gimple_no_warning_p (stmt), > + stmt, 0); > return changed; > } > > /* Valueziation callback that ends up not following SSA edges. */ > > tree > no_follow_ssa_edges (tree) > { > return NULL_TREE; > } > Index: trunk4/gcc/match.pd > =================================================================== > --- trunk4/gcc/match.pd (revision 235452) > +++ trunk4/gcc/match.pd (working copy) > @@ -3099,10 +3099,54 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > (simplify > /* signbit(x) -> 0 if x is nonnegative. */ > (SIGNBIT tree_expr_nonnegative_p@0) > { integer_zero_node; }) > > (simplify > /* signbit(x) -> x<0 if x doesn't have signed zeros. */ > (SIGNBIT @0) > (if (!HONOR_SIGNED_ZEROS (@0)) > (convert (lt @0 { build_real (TREE_TYPE (@0), dconst0); })))) > + > +/* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 -+ C1. */ > +(for cmp (eq ne) > + (for op (plus minus) > + rop (minus plus) > + (simplify > + (cmp (op@3 @0 INTEGER_CST@1) INTEGER_CST@2) > + (if (!TREE_OVERFLOW (@1) && !TREE_OVERFLOW (@2) > + && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0)) > + && !TYPE_OVERFLOW_TRAPS (TREE_TYPE (@0)) > + && !TYPE_SATURATING (TREE_TYPE (@0))) > + (with { tree res = int_const_binop (rop, @2, @1); } > + (if (TREE_OVERFLOW (res)) > + { constant_boolean_node (cmp == NE_EXPR, type); } > + (if (single_use (@3)) > + (cmp @0 { res; })))))))) > +(for cmp (lt le gt ge) > + (for op (plus minus) > + rop (minus plus) > + (simplify > + (cmp (op@3 @0 INTEGER_CST@1) INTEGER_CST@2) > + (if (!TREE_OVERFLOW (@1) && !TREE_OVERFLOW (@2) > + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))) > + (with { tree res = int_const_binop (rop, @2, @1); } > + (if (TREE_OVERFLOW (res)) > + { > + fold_overflow_warning (("assuming signed overflow does not occur " > + "when simplifying conditional to constant"), > + WARN_STRICT_OVERFLOW_CONDITIONAL); > + bool less = cmp == LE_EXPR || cmp == LT_EXPR; > + /* wi::ges_p (@2, 0) should be sufficient for a signed type. */ > + bool ovf_high = wi::lt_p (@1, 0, TYPE_SIGN (TREE_TYPE (@1))) > + != (op == MINUS_EXPR); > + constant_boolean_node (less == ovf_high, type); > + } > + (if (single_use (@3)) > + (with > + { > + fold_overflow_warning (("assuming signed overflow does not occur " > + "when changing X +- C1 cmp C2 to " > + "X cmp C2 -+ C1"), > + WARN_STRICT_OVERFLOW_COMPARISON); > + } > + (cmp @0 { res; }))))))))) > Index: trunk4/gcc/testsuite/gcc.dg/tree-ssa/20040305-1.c > =================================================================== > --- trunk4/gcc/testsuite/gcc.dg/tree-ssa/20040305-1.c (revision 235452) > +++ trunk4/gcc/testsuite/gcc.dg/tree-ssa/20040305-1.c (working copy) > @@ -16,15 +16,15 @@ void foo(int edx, int eax) > } > if (eax == 100) > { > if (-- edx == 0) > afred[0] = 2; > } > } > > > /* Verify that we did a forward propagation. */ > -/* { dg-final { scan-tree-dump-times "Replaced" 1 "forwprop1"} } */ > +/* { dg-final { scan-tree-dump-times "gimple_simplified" 1 "forwprop1"} } > */ > > /* After cddce we should have two IF statements remaining as the other > two tests can be threaded. */ > /* { dg-final { scan-tree-dump-times "if " 2 "cddce2"} } */ >