> So - which case is it? IIRC we want to handle small signed > constants but the code can end up unsigned. For the > above we could write (unsigned long)((int)a + 1 - 1) and thus > sign-extend? Or even avoid this if we know the range. > That is, it becomes the first case again (operation performed > in a smaller type).
Both :) But in order to move forward the second transform suffices to get rid of the redundant subtraction/addition of the ivopts candidate. Attached is a new version as single file that disregards the other possible cases (3/3 from before), only performs this transform and checks for gimple_simplified in vrp2 after ivopts now. Bootstrapped, no regressions on s390 and x86. Regards Robin
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index a6e33833680..99ec5f34319 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -5428,8 +5428,9 @@ gfc_conv_intrinsic_findloc (gfc_se *se, gfc_expr *expr) tree type; tree tmp; tree found; - tree forward_branch; - tree back_branch; + /* Initialize here to avoid 'maybe used uninitialized'. */ + tree forward_branch = NULL_TREE; + tree back_branch = NULL_TREE; gfc_loopinfo loop; gfc_ss *arrayss; gfc_ss *maskss; diff --git a/gcc/gimple-loop-versioning.cc b/gcc/gimple-loop-versioning.cc index 8fa19488490..35344b7b448 100644 --- a/gcc/gimple-loop-versioning.cc +++ b/gcc/gimple-loop-versioning.cc @@ -1266,6 +1266,12 @@ loop_versioning::record_address_fragment (gimple *stmt, continue; } } + if (CONVERT_EXPR_CODE_P (code)) + { + tree op1 = gimple_assign_rhs1 (assign); + address->terms[i].expr = strip_casts (op1); + continue; + } } i += 1; } diff --git a/gcc/match.pd b/gcc/match.pd index 0317bc704f7..22282615f84 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -2020,6 +2020,37 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (cst && !TREE_OVERFLOW (cst)) (plus { cst; } @0)))) +/* ((T)(A)) + CST -> (T)(A + CST) */ +#if GIMPLE + (simplify + (plus (convert SSA_NAME@0) INTEGER_CST@1) + (if (TREE_CODE (TREE_TYPE (@0)) == INTEGER_TYPE + && TREE_CODE (type) == INTEGER_TYPE + && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0)) + && int_fits_type_p (@1, TREE_TYPE (@0))) + /* Perform binary operation inside the cast if the constant fits + and (A + CST)'s range does not overflow. */ + (with + { + wi::overflow_type min_ovf = wi::OVF_OVERFLOW, + max_ovf = wi::OVF_OVERFLOW; + tree inner_type = TREE_TYPE (@0); + + wide_int w1 = wide_int::from (wi::to_wide (@1), TYPE_PRECISION (inner_type), + TYPE_SIGN (inner_type)); + + wide_int wmin0, wmax0; + if (get_range_info (@0, &wmin0, &wmax0) == VR_RANGE) + { + wi::add (wmin0, w1, TYPE_SIGN (inner_type), &min_ovf); + wi::add (wmax0, w1, TYPE_SIGN (inner_type), &max_ovf); + } + } + (if (min_ovf == wi::OVF_NONE && max_ovf == wi::OVF_NONE) + (convert (plus @0 { wide_int_to_tree (TREE_TYPE (@0), w1); } ))) + ))) +#endif + /* ~A + A -> -1 */ (simplify (plus:c (bit_not @0) @0) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-5.c b/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-5.c index 3d9940558cb..7f2e4dc2e4d 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-5.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-5.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-ch2-details" } */ +/* { dg-options "-O2 -fno-tree-ccp -fno-tree-vrp -fdump-tree-ch2-details" } */ int is_sorted(int *a, int n) { diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-7.c b/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-7.c index a0a6e6a9b57..58b341c392c 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-7.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/copy-headers-7.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-ch2-details --param logical-op-non-short-circuit=0" } */ +/* { dg-options "-O2 -fno-tree-ccp -fno-tree-vrp -fdump-tree-ch2-details --param logical-op-non-short-circuit=0" } */ int is_sorted(int *a, int n, int m, int k) { diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-16.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-16.c index 1bef7e7a31f..bef76e597dd 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-16.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-16.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O -fdump-tree-forwprop1" } */ +/* { dg-options "-O -fdump-tree-forwprop2" } */ int foo (double xx, double xy) { @@ -10,4 +10,4 @@ int foo (double xx, double xy) return 2; } -/* { dg-final { scan-tree-dump "if \\\(x" "forwprop1" } } */ +/* { dg-final { scan-tree-dump "if \\\(x" "forwprop2" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-15.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-15.c index b437518487d..dce6ad57a04 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/loop-15.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/loop-15.c @@ -19,7 +19,7 @@ int bla(void) } /* Since the loop is removed, there should be no addition. */ -/* { dg-final { scan-tree-dump-times " \\+ " 0 "optimized" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump-times " \\+ " 0 "optimized" } } */ /* { dg-final { scan-tree-dump-times " \\* " 1 "optimized" } } */ /* The if from the loop header copying remains in the code. */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr23744.c b/gcc/testsuite/gcc.dg/tree-ssa/pr23744.c index 3385aa1e424..ba3fda352ca 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr23744.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr23744.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fno-tree-ccp -fdisable-tree-evrp -fdump-tree-vrp1" } */ +/* { dg-options "-O2 -fno-tree-ccp -fdisable-tree-evrp -fdump-tree-vrp1-details" } */ void h (void); @@ -17,4 +17,4 @@ int g (int i, int j) return 1; } -/* { dg-final { scan-tree-dump-times "Folding predicate.*to 1" 1 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified" 1 "vrp1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr52631.c b/gcc/testsuite/gcc.dg/tree-ssa/pr52631.c index c18a5d570b4..2e99d112057 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr52631.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr52631.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fno-tree-forwprop -fdump-tree-fre1-details" } */ +/* { dg-options "-O2 -fno-tree-forwprop -fdump-tree-ccp1-details" } */ unsigned f(unsigned a) { @@ -12,6 +12,6 @@ unsigned f(unsigned a) } /* We want to verify that we replace the b & 1 with b. */ -/* { dg-final { scan-tree-dump-times "Replaced b_\[0-9\]+ & 1 with b_\[0-9\]+ in" 1 "fre1"} } */ +/* { dg-final { scan-tree-dump-times "Match-and-simplified b_\[0-9\]+ & 1 to b_\[0-9\]+" 1 "ccp1"} } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-over-widen-23.c b/gcc/testsuite/gcc.dg/vect/vect-over-widen-23.c index 34ce512f372..e2e0d6cb8bc 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-over-widen-23.c +++ b/gcc/testsuite/gcc.dg/vect/vect-over-widen-23.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-additional-options "-fno-tree-forwprop -fno-tree-vrp" } +/* { dg-additional-options "-fno-tree-forwprop -fno-tree-vrp -fno-tree-ccp -fno-tree-copy-prop" } */ /* { dg-require-effective-target vect_int } */ #include "tree-vect.h" diff --git a/gcc/testsuite/gcc.dg/wrapped-binop-simplify.c b/gcc/testsuite/gcc.dg/wrapped-binop-simplify.c new file mode 100644 index 00000000000..44d85c04bfb --- /dev/null +++ b/gcc/testsuite/gcc.dg/wrapped-binop-simplify.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-vrp2-details" } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to" 4 "vrp2" } } */ + +void v1 (unsigned long *in, unsigned long *out, unsigned int n) +{ + int i; + + for (i = 0; i < n; i++) + { + out[i] = in[i]; + } +} + +void v2 (unsigned long *in, unsigned long *out, int n) +{ + int i; + + for (i = 0; i < n; i++) + { + out[i] = in[i]; + } +} + +void v3 (unsigned long *in, unsigned long *out, unsigned int n) +{ + unsigned int i; + + for (i = 0; i < n; i++) + { + out[i] = in[i]; + } +} + +void v4 (unsigned long *in, unsigned long *out, int n) +{ + unsigned int i; + + for (i = 0; i < n; i++) + { + out[i] = in[i]; + } +} diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c index 0862f83e9a1..40621709036 100644 --- a/gcc/tree-ssa-propagate.c +++ b/gcc/tree-ssa-propagate.c @@ -814,7 +814,6 @@ ssa_propagation_engine::ssa_propagate (void) ssa_prop_fini (); } - /* Return true if STMT is of the form 'mem_ref = RHS', where 'mem_ref' is a non-volatile pointer dereference, a structure reference or a reference to a single _DECL. Ignore volatile memory references @@ -1072,6 +1071,15 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb) gimple_set_modified (stmt, true); } + /* Also fold if we want to fold all statements. */ + if (!did_replace && substitute_and_fold_engine->fold_all_stmts + && fold_stmt (&i, follow_single_use_edges)) + { + did_replace = true; + stmt = gsi_stmt (i); + gimple_set_modified (stmt, true); + } + /* Some statements may be simplified using propagator specific information. Do this before propagating into the stmt to not disturb pass specific information. */ diff --git a/gcc/tree-ssa-propagate.h b/gcc/tree-ssa-propagate.h index 81b635e0787..0606b21dbd2 100644 --- a/gcc/tree-ssa-propagate.h +++ b/gcc/tree-ssa-propagate.h @@ -100,6 +100,7 @@ class ssa_propagation_engine class substitute_and_fold_engine { public: + substitute_and_fold_engine () : fold_all_stmts (false) { } virtual ~substitute_and_fold_engine (void) { } virtual bool fold_stmt (gimple_stmt_iterator *) { return false; } virtual tree get_value (tree) { return NULL_TREE; } @@ -107,6 +108,12 @@ class substitute_and_fold_engine bool substitute_and_fold (basic_block = NULL); bool replace_uses_in (gimple *); bool replace_phi_args_in (gphi *); + + void set_fold_all_stmts () { fold_all_stmts = true; } + + /* Users like VRP can set this when they want to perform + folding for every propagation. */ + bool fold_all_stmts; }; #endif /* _TREE_SSA_PROPAGATE_H */ diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index e2850682da2..9328c2edaae 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -6693,6 +6693,7 @@ vrp_prop::vrp_finalize (bool warn_array_bounds_p) set_all_edges_as_executable (cfun); class vrp_folder vrp_folder; + vrp_folder.set_fold_all_stmts (); vrp_folder.vr_values = &vr_values; vrp_folder.substitute_and_fold ();