Commit 1cab645d by Richard Biener Committed by Richard Biener

re PR tree-optimization/87105 (Autovectorization [X86, SSE2, AVX2, DoublePrecision])

2018-10-23  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/87105
	PR tree-optimization/87608
	* passes.def (pass_all_early_optimizations): Add early phi-opt
	after dce.
	* tree-ssa-phiopt.c (value_replacement): Ignore NOPs and predicts in
	addition to debug stmts.
	(tree_ssa_phiopt_worker): Add early_p argument, do only min/max
	and abs replacement early.
	* tree-cfg.c (gimple_empty_block_p): Likewise.

	* g++.dg/tree-ssa/phiopt-1.C: New testcase.
	g++.dg/vect/slp-pr87105.cc: Likewise.
	* g++.dg/tree-ssa/pr21463.C: Scan phiopt2 because this testcase
	relies on phiprop run before.
	* g++.dg/tree-ssa/pr30738.C: Likewise.
	* g++.dg/tree-ssa/pr57380.C: Likewise.
	* gcc.dg/tree-ssa/pr84859.c: Likewise.
	* gcc.dg/tree-ssa/pr45397.c: Scan phiopt2 because phiopt1 is
	confused by copies in the IL left by EVRP.
	* gcc.dg/tree-ssa/phi-opt-5.c: Likewise, this time confused
	by predictors.
	* gcc.dg/tree-ssa/phi-opt-12.c: Scan phiopt2.
	* gcc.dg/pr24574.c: Likewise.
	* g++.dg/tree-ssa/pr86544.C: Scan phiopt4.

From-SVN: r265421
parent 7a433140
2018-10-23 Richard Biener <rguenther@suse.de>
PR tree-optimization/87105
PR tree-optimization/87608
* passes.def (pass_all_early_optimizations): Add early phi-opt
after dce.
* tree-ssa-phiopt.c (value_replacement): Ignore NOPs and predicts in
addition to debug stmts.
(tree_ssa_phiopt_worker): Add early_p argument, do only min/max
and abs replacement early.
* tree-cfg.c (gimple_empty_block_p): Likewise.
2018-10-23 Richard Earnshaw <rearnsha@arm.com> 2018-10-23 Richard Earnshaw <rearnsha@arm.com>
PR target/86383 PR target/86383
...@@ -88,6 +88,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -88,6 +88,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_merge_phi); NEXT_PASS (pass_merge_phi);
NEXT_PASS (pass_dse); NEXT_PASS (pass_dse);
NEXT_PASS (pass_cd_dce); NEXT_PASS (pass_cd_dce);
NEXT_PASS (pass_phiopt, true /* early_p */);
NEXT_PASS (pass_early_ipa_sra); NEXT_PASS (pass_early_ipa_sra);
NEXT_PASS (pass_tail_recursion); NEXT_PASS (pass_tail_recursion);
NEXT_PASS (pass_convert_switch); NEXT_PASS (pass_convert_switch);
...@@ -208,7 +209,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -208,7 +209,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_copy_prop); NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_tree_ifcombine); NEXT_PASS (pass_tree_ifcombine);
NEXT_PASS (pass_merge_phi); NEXT_PASS (pass_merge_phi);
NEXT_PASS (pass_phiopt); NEXT_PASS (pass_phiopt, false /* early_p */);
NEXT_PASS (pass_tail_recursion); NEXT_PASS (pass_tail_recursion);
NEXT_PASS (pass_ch); NEXT_PASS (pass_ch);
NEXT_PASS (pass_lower_complex); NEXT_PASS (pass_lower_complex);
...@@ -237,7 +238,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -237,7 +238,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_reassoc, true /* insert_powi_p */); NEXT_PASS (pass_reassoc, true /* insert_powi_p */);
NEXT_PASS (pass_dce); NEXT_PASS (pass_dce);
NEXT_PASS (pass_forwprop); NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_phiopt); NEXT_PASS (pass_phiopt, false /* early_p */);
NEXT_PASS (pass_ccp, true /* nonzero_p */); NEXT_PASS (pass_ccp, true /* nonzero_p */);
/* After CCP we rewrite no longer addressed locals into SSA /* After CCP we rewrite no longer addressed locals into SSA
form if possible. */ form if possible. */
...@@ -328,7 +329,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -328,7 +329,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_dse); NEXT_PASS (pass_dse);
NEXT_PASS (pass_cd_dce); NEXT_PASS (pass_cd_dce);
NEXT_PASS (pass_forwprop); NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_phiopt); NEXT_PASS (pass_phiopt, false /* early_p */);
NEXT_PASS (pass_fold_builtins); NEXT_PASS (pass_fold_builtins);
NEXT_PASS (pass_optimize_widening_mul); NEXT_PASS (pass_optimize_widening_mul);
NEXT_PASS (pass_store_merging); NEXT_PASS (pass_store_merging);
......
2018-10-23 Richard Biener <rguenther@suse.de> 2018-10-23 Richard Biener <rguenther@suse.de>
PR tree-optimization/87105
PR tree-optimization/87608
* g++.dg/tree-ssa/phiopt-1.C: New testcase.
g++.dg/vect/slp-pr87105.cc: Likewise.
* g++.dg/tree-ssa/pr21463.C: Scan phiopt2 because this testcase
relies on phiprop run before.
* g++.dg/tree-ssa/pr30738.C: Likewise.
* g++.dg/tree-ssa/pr57380.C: Likewise.
* gcc.dg/tree-ssa/pr84859.c: Likewise.
* gcc.dg/tree-ssa/pr45397.c: Scan phiopt2 because phiopt1 is
confused by copies in the IL left by EVRP.
* gcc.dg/tree-ssa/phi-opt-5.c: Likewise, this time confused
by predictors.
* gcc.dg/tree-ssa/phi-opt-12.c: Scan phiopt2.
* gcc.dg/pr24574.c: Likewise.
* g++.dg/tree-ssa/pr86544.C: Scan phiopt4.
2018-10-23 Richard Biener <rguenther@suse.de>
PR tree-optimization/87700 PR tree-optimization/87700
* gcc.dg/torture/pr87700.c: New testcase. * gcc.dg/torture/pr87700.c: New testcase.
......
// { dg-do compile }
// { dg-options "-O -fdump-tree-phiopt1" }
#define cond_swap5(a,b);\
t = *(a);\
*(a) = (t<*(b))?t:*(b);\
*(b) = (t<*(b))?*(b):t;
template<int n>
void static_sort1(int *a){
return;
}
template<>
void static_sort1<32>(int* first){
int t;
static_sort1<16>(first);
static_sort1<16>(first+16);
cond_swap5(first + 0u, first + 16u);
cond_swap5(first + 8u, first + 24u);
cond_swap5(first + 8u, first + 16u);
cond_swap5(first + 4u, first + 20u);
cond_swap5(first + 12u, first + 28u);
cond_swap5(first + 12u, first + 20u);
cond_swap5(first + 4u, first + 8u);
cond_swap5(first + 12u, first + 16u);
cond_swap5(first + 20u, first + 24u);
cond_swap5(first + 2u, first + 18u);
cond_swap5(first + 10u, first + 26u);
cond_swap5(first + 10u, first + 18u);
cond_swap5(first + 6u, first + 22u);
cond_swap5(first + 14u, first + 30u);
cond_swap5(first + 14u, first + 22u);
cond_swap5(first + 6u, first + 10u);
cond_swap5(first + 14u, first + 18u);
cond_swap5(first + 22u, first + 26u);
cond_swap5(first + 2u, first + 4u);
cond_swap5(first + 6u, first + 8u);
cond_swap5(first + 10u, first + 12u);
cond_swap5(first + 14u, first + 16u);
cond_swap5(first + 18u, first + 20u);
cond_swap5(first + 22u, first + 24u);
cond_swap5(first + 26u, first + 28u);
cond_swap5(first + 1u, first + 17u);
cond_swap5(first + 9u, first + 25u);
cond_swap5(first + 9u, first + 17u);
cond_swap5(first + 5u, first + 21u);
cond_swap5(first + 13u, first + 29u);
cond_swap5(first + 13u, first + 21u);
cond_swap5(first + 5u, first + 9u);
cond_swap5(first + 13u, first + 17u);
cond_swap5(first + 21u, first + 25u);
cond_swap5(first + 3u, first + 19u);
cond_swap5(first + 11u, first + 27u);
cond_swap5(first + 11u, first + 19u);
cond_swap5(first + 7u, first + 23u);
cond_swap5(first + 15u, first + 31u);
cond_swap5(first + 15u, first + 23u);
cond_swap5(first + 7u, first + 11u);
cond_swap5(first + 15u, first + 19u);
cond_swap5(first + 23u, first + 27u);
cond_swap5(first + 3u, first + 5u);
cond_swap5(first + 7u, first + 9u);
cond_swap5(first + 11u, first + 13u);
cond_swap5(first + 15u, first + 17u);
cond_swap5(first + 19u, first + 21u);
cond_swap5(first + 23u, first + 25u);
cond_swap5(first + 27u, first + 29u);
cond_swap5(first + 1u, first + 2u);
cond_swap5(first + 3u, first + 4u);
cond_swap5(first + 5u, first + 6u);
cond_swap5(first + 7u, first + 8u);
cond_swap5(first + 9u, first + 10u);
cond_swap5(first + 11u, first + 12u);
cond_swap5(first + 13u, first + 14u);
cond_swap5(first + 15u, first + 16u);
cond_swap5(first + 17u, first + 18u);
cond_swap5(first + 19u, first + 20u);
cond_swap5(first + 21u, first + 22u);
cond_swap5(first + 23u, first + 24u);
cond_swap5(first + 25u, first + 26u);
cond_swap5(first + 27u, first + 28u);
cond_swap5(first + 29u, first + 30u);
};
void foo(int *a)
{
static_sort1<32>(a);
}
// { dg-final { scan-tree-dump-not "if " "phiopt1" } }
// { dg-final { scan-tree-dump-times "MIN" 65 "phiopt1" } }
// { dg-final { scan-tree-dump-times "MAX" 65 "phiopt1" } }
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O -fdump-tree-phiopt1" } */ /* { dg-options "-O -fdump-tree-phiopt2" } */
template<class T> static inline const T &ref_max(const T &a, const T &b) template<class T> static inline const T &ref_max(const T &a, const T &b)
{ return a<b ? b : a; } { return a<b ? b : a; }
...@@ -15,5 +15,5 @@ template<class T> struct foo_t { ...@@ -15,5 +15,5 @@ template<class T> struct foo_t {
template struct foo_t<int>; template struct foo_t<int>;
/* { dg-final { scan-tree-dump-times "MIN_EXPR" 2 "phiopt1" } } */ /* { dg-final { scan-tree-dump-times "MIN_EXPR" 2 "phiopt2" } } */
/* { dg-final { scan-tree-dump-times "MAX_EXPR" 2 "phiopt1" } } */ /* { dg-final { scan-tree-dump-times "MAX_EXPR" 2 "phiopt2" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O -fdump-tree-phiopt1" } */ /* { dg-options "-O -fdump-tree-phiopt2" } */
template <class T> template <class T>
static inline const T& static inline const T&
...@@ -13,4 +13,4 @@ int test_min_ref (int x, int y) ...@@ -13,4 +13,4 @@ int test_min_ref (int x, int y)
return min_ref (x, y); return min_ref (x, y);
} }
/* { dg-final { scan-tree-dump "MIN_EXPR" "phiopt1" } } */ /* { dg-final { scan-tree-dump "MIN_EXPR" "phiopt2" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-phiopt1" } */ /* { dg-options "-O2 -fdump-tree-phiopt2" } */
/* { dg-add-options bind_pic_locally } */ /* { dg-add-options bind_pic_locally } */
struct my_array { struct my_array {
...@@ -18,4 +18,4 @@ int f(my_array a, my_array b) { ...@@ -18,4 +18,4 @@ int f(my_array a, my_array b) {
return res; return res;
} }
/* { dg-final { scan-tree-dump "MAX_EXPR" "phiopt1" } } */ /* { dg-final { scan-tree-dump "MAX_EXPR" "phiopt2" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-phiopt3 -fdump-tree-optimized" } */ /* { dg-options "-O2 -fdump-tree-phiopt4 -fdump-tree-optimized" } */
int PopCount (long b) { int PopCount (long b) {
int c = 0; int c = 0;
...@@ -12,4 +12,4 @@ int PopCount (long b) { ...@@ -12,4 +12,4 @@ int PopCount (long b) {
} }
/* { dg-final { scan-tree-dump-times "__builtin_popcount" 1 "optimized" } } */ /* { dg-final { scan-tree-dump-times "__builtin_popcount" 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times "if" 0 "phiopt3" } } */ /* { dg-final { scan-tree-dump-times "if" 0 "phiopt4" } } */
// { dg-do compile }
// { dg-require-effective-target c++11 }
// { dg-require-effective-target vect_double }
// For MIN/MAX recognition
// { dg-additional-options "-ffast-math -fvect-cost-model" }
#include <algorithm>
#include <cmath>
#include <stdint.h>
// Point structure [x, y]
struct Point {
double x, y;
inline Point() noexcept = default;
constexpr Point(const Point&) noexcept = default;
constexpr Point(double x, double y) noexcept
: x(x), y(y) {}
};
// Box structure [x0, y0, x1, y1]
struct Box {
double x0, y0, x1, y1;
inline void reset(double x0, double y0, double x1, double y1) noexcept {
this->x0 = x0;
this->y0 = y0;
this->x1 = x1;
this->y1 = y1;
}
};
// Overloads to make vector processing simpler.
static constexpr Point operator-(const Point& a) noexcept { return Point(-a.x, -a.y); }
static constexpr Point operator+(const Point& a, double b) noexcept
{ return Point(a.x + b, a.y + b); }
static constexpr Point operator-(const Point& a, double b) noexcept
{ return Point(a.x - b, a.y - b); }
static constexpr Point operator*(const Point& a, double b) noexcept
{ return Point(a.x * b, a.y * b); }
static constexpr Point operator/(const Point& a, double b) noexcept
{ return Point(a.x / b, a.y / b); }
static constexpr Point operator+(const Point& a, const Point& b) noexcept
{ return Point(a.x + b.x, a.y + b.y); }
static constexpr Point operator-(const Point& a, const Point& b) noexcept
{ return Point(a.x - b.x, a.y - b.y); }
static constexpr Point operator*(const Point& a, const Point& b) noexcept
{ return Point(a.x * b.x, a.y * b.y); }
static constexpr Point operator/(const Point& a, const Point& b) noexcept
{ return Point(a.x / b.x, a.y / b.y); }
static constexpr Point operator+(double a, const Point& b) noexcept
{ return Point(a + b.x, a + b.y); }
static constexpr Point operator-(double a, const Point& b) noexcept
{ return Point(a - b.x, a - b.y); }
static constexpr Point operator*(double a, const Point& b) noexcept
{ return Point(a * b.x, a * b.y); }
static constexpr Point operator/(double a, const Point& b) noexcept
{ return Point(a / b.x, a / b.y); }
// Min/Max - different semantics compared to std.
template<typename T> constexpr T myMin(const T& a, const T& b) noexcept
{ return b < a ? b : a; }
template<typename T> constexpr T myMax(const T& a, const T& b) noexcept
{ return a < b ? b : a; }
// Linear interpolation, works with points as well.
template<typename V, typename T = double>
inline V lerp(const V& a, const V& b, const T& t) noexcept {
return (a * (1.0 - t)) + (b * t);
}
// Merge a point into a box by possibly increasing its bounds.
inline void boxMergePoint(Box& box, const Point& p) noexcept {
box.x0 = myMin(box.x0, p.x);
box.y0 = myMin(box.y0, p.y);
box.x1 = myMax(box.x1, p.x);
box.y1 = myMax(box.y1, p.y);
}
void quadBoundingBoxA(const Point bez[3], Box& bBox) noexcept {
// Bounding box of start and end points.
bBox.reset(myMin(bez[0].x, bez[2].x), myMin(bez[0].y, bez[2].y),
myMax(bez[0].x, bez[2].x), myMax(bez[0].y, bez[2].y));
Point t = (bez[0] - bez[1]) / (bez[0] - bez[1] * 2.0 + bez[2]);
t.x = myMax(t.x, 0.0);
t.y = myMax(t.y, 0.0);
t.x = myMin(t.x, 1.0);
t.y = myMin(t.y, 1.0);
boxMergePoint(bBox, lerp(lerp(bez[0], bez[1], t),
lerp(bez[1], bez[2], t), t));
}
// We should have if-converted everything down to straight-line code
// { dg-final { scan-tree-dump-times "<bb \[0-9\]+>" 1 "slp2" } }
// We fail to elide an earlier store which makes us not handle a later
// duplicate one for vectorization.
// { dg-final { scan-tree-dump-times "basic block part vectorized" 1 "slp2" { xfail *-*-* } } }
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O -fdump-tree-phiopt1" } */ /* { dg-options "-O -fdump-tree-phiopt2" } */
int f0(int i) int f0(int i)
{ {
...@@ -33,4 +33,4 @@ int f5(int i) ...@@ -33,4 +33,4 @@ int f5(int i)
/* We should if-convert all functions to carry out the operation /* We should if-convert all functions to carry out the operation
unconditionally. */ unconditionally. */
/* { dg-final { scan-tree-dump-not "= PHI" "phiopt1" } } */ /* { dg-final { scan-tree-dump-not "= PHI" "phiopt2" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-phiopt1-details" } */ /* { dg-options "-O1 -fdump-tree-phiopt2-details" } */
int t( int i) int t( int i)
{ {
...@@ -15,4 +15,4 @@ end: ...@@ -15,4 +15,4 @@ end:
} }
/* Should have no ifs left after straightening. */ /* Should have no ifs left after straightening. */
/* { dg-final { scan-tree-dump-times "if " 0 "phiopt1"} } */ /* { dg-final { scan-tree-dump-times "if " 0 "phiopt2"} } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-phiopt1-details" } */ /* { dg-options "-O1 -fdump-tree-phiopt2-details" } */
int f(int a, int b) int f(int a, int b)
{ {
int c = b; int c = b;
...@@ -9,4 +9,4 @@ int f(int a, int b) ...@@ -9,4 +9,4 @@ int f(int a, int b)
} }
/* Should have no ifs left after straightening. */ /* Should have no ifs left after straightening. */
/* { dg-final { scan-tree-dump-times "if " 0 "phiopt1"} } */ /* { dg-final { scan-tree-dump-times "if " 0 "phiopt2"} } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O -fdump-tree-phiopt1" } */ /* { dg-options "-O -fdump-tree-phiopt2" } */
int f(int a, int b, int c) { int f(int a, int b, int c) {
if (c > 5) return c; if (c > 5) return c;
...@@ -19,4 +19,4 @@ unsigned m(unsigned a, unsigned b) { ...@@ -19,4 +19,4 @@ unsigned m(unsigned a, unsigned b) {
return a & b; return a & b;
} }
/* { dg-final { scan-tree-dump-times "goto" 2 "phiopt1" } } */ /* { dg-final { scan-tree-dump-times "goto" 2 "phiopt2" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O1 -ffinite-math-only -fno-signed-zeros -fdump-tree-phiopt1" } */ /* { dg-options "-O1 -ffinite-math-only -fno-signed-zeros -fdump-tree-phiopt" } */
float repl1 (float varx) float repl1 (float varx)
{ {
...@@ -16,8 +16,11 @@ float repl1 (float varx) ...@@ -16,8 +16,11 @@ float repl1 (float varx)
varx_4 = MIN_EXPR <1.0e+0, varx_2>; varx_4 = MIN_EXPR <1.0e+0, varx_2>;
varx_5 = MAX_EXPR <varx_4, 0.0>; */ varx_5 = MAX_EXPR <varx_4, 0.0>; */
/* { dg-final { scan-tree-dump "varx.*MIN_EXPR.*1\\.0" "phiopt1"} } */ /* phiopt1 confused by predictors. */
/* { dg-final { scan-tree-dump "varx.*MAX_EXPR.*0\\.0" "phiopt1"} } */ /* { dg-final { scan-tree-dump "varx.*MIN_EXPR.*1\\.0" "phiopt1" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump "varx.*MAX_EXPR.*0\\.0" "phiopt1" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump "varx.*MIN_EXPR.*1\\.0" "phiopt2"} } */
/* { dg-final { scan-tree-dump "varx.*MAX_EXPR.*0\\.0" "phiopt2"} } */
float repl2 (float vary) float repl2 (float vary)
{ {
...@@ -34,8 +37,11 @@ float repl2 (float vary) ...@@ -34,8 +37,11 @@ float repl2 (float vary)
vary_4 = MAX_EXPR <0.0, vary_2>; vary_4 = MAX_EXPR <0.0, vary_2>;
vary_5 = MIN_EXPR <vary_4, 1.0e+0>; */ vary_5 = MIN_EXPR <vary_4, 1.0e+0>; */
/* { dg-final { scan-tree-dump "vary.*MAX_EXPR.*0\\.0" "phiopt1"} } */ /* phiopt1 confused by predictors. */
/* { dg-final { scan-tree-dump "vary.*MIN_EXPR.*1\\.0" "phiopt1"} } */ /* { dg-final { scan-tree-dump "vary.*MAX_EXPR.*0\\.0" "phiopt1" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump "vary.*MIN_EXPR.*1\\.0" "phiopt1" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump "vary.*MAX_EXPR.*0\\.0" "phiopt2"} } */
/* { dg-final { scan-tree-dump "vary.*MIN_EXPR.*1\\.0" "phiopt2"} } */
float repl3 (float varz, float vara, float varb) float repl3 (float varz, float vara, float varb)
{ {
...@@ -54,5 +60,7 @@ float repl3 (float varz, float vara, float varb) ...@@ -54,5 +60,7 @@ float repl3 (float varz, float vara, float varb)
<L1>:; <L1>:;
vara_6 = MAX_EXPR <varb_5, varz_2>; */ vara_6 = MAX_EXPR <varb_5, varz_2>; */
/* { dg-final { scan-tree-dump "if .*varz" "phiopt1"} } */ /* phiopt1 confused by predictors. */
/* { dg-final { scan-tree-dump "vara.*MAX_EXPR" "phiopt1"} } */ /* { dg-final { scan-tree-dump "vara.*MAX_EXPR" "phiopt1" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump "if .*varz" "phiopt2"} } */
/* { dg-final { scan-tree-dump "vara.*MAX_EXPR" "phiopt2"} } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O -fdump-tree-phiopt1" } */ /* { dg-options "-O -fdump-tree-phiopt2" } */
struct C { int i; }; struct C { int i; };
int *g(struct C *p) int *g(struct C *p)
...@@ -9,4 +9,4 @@ int *g(struct C *p) ...@@ -9,4 +9,4 @@ int *g(struct C *p)
return (int *)0; return (int *)0;
} }
/* { dg-final { scan-tree-dump-not "if" "phiopt1" } } */ /* { dg-final { scan-tree-dump-not "if" "phiopt2" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O -fdump-tree-optimized -fdump-tree-phiopt1" } */ /* { dg-options "-O -fdump-tree-optimized -fdump-tree-phiopt2" } */
int g(int,int); int g(int,int);
int f(int t, int c) int f(int t, int c)
...@@ -19,6 +19,6 @@ int f(int t, int c) ...@@ -19,6 +19,6 @@ int f(int t, int c)
but currently is not as PHI-OPT does not reduce the t PHI as we have but currently is not as PHI-OPT does not reduce the t PHI as we have
two phis. Note this is fixed with two phis. Note this is fixed with
http://gcc.gnu.org/ml/gcc-patches/2012-01/msg01195.html . */ http://gcc.gnu.org/ml/gcc-patches/2012-01/msg01195.html . */
/* { dg-final { scan-tree-dump-not "if" "phiopt1" } } */ /* { dg-final { scan-tree-dump-not "if" "phiopt2" } } */
/* { dg-final { scan-tree-dump "g .t_\[0-9\]*.D.," "optimized" } } */ /* { dg-final { scan-tree-dump "g .t_\[0-9\]*.D.," "optimized" } } */
/* { dg-final { scan-tree-dump-not "PHI" "optimized" } } */ /* { dg-final { scan-tree-dump-not "PHI" "optimized" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-phiopt3 -fdump-tree-optimized" } */ /* { dg-options "-O2 -fdump-tree-phiopt4 -fdump-tree-optimized" } */
int PopCount (long b) { int PopCount (long b) {
int c = 0; int c = 0;
...@@ -12,4 +12,4 @@ int PopCount (long b) { ...@@ -12,4 +12,4 @@ int PopCount (long b) {
} }
/* { dg-final { scan-tree-dump-times "__builtin_popcount" 1 "optimized" } } */ /* { dg-final { scan-tree-dump-times "__builtin_popcount" 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times "if" 0 "phiopt3" } } */ /* { dg-final { scan-tree-dump-times "if" 0 "phiopt4" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-phiopt1 -fdump-tree-evrp" } */ /* { dg-options "-O2 -fdump-tree-phiopt -fdump-tree-evrp" } */
int foo_add (const unsigned char *tmp, int i, int val) int foo_add (const unsigned char *tmp, int i, int val)
{ {
...@@ -18,7 +18,12 @@ int foo_mul (const unsigned char *tmp, int i, int val) ...@@ -18,7 +18,12 @@ int foo_mul (const unsigned char *tmp, int i, int val)
/* All cases should end up using min/max for the saturated operations and /* All cases should end up using min/max for the saturated operations and
have no control flow. */ have no control flow. */
/* EVRP leaves copies in the IL which confuses phiopt1 so we have
to rely on phiopt2 instead. */
/* { dg-final { scan-tree-dump-not " & 255;" "evrp" } } */ /* { dg-final { scan-tree-dump-not " & 255;" "evrp" } } */
/* { dg-final { scan-tree-dump-times "MAX_EXPR" 3 "phiopt1" } } */ /* { dg-final { scan-tree-dump-times "MAX_EXPR" 3 "phiopt1" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump-times "MIN_EXPR" 3 "phiopt1" } } */ /* { dg-final { scan-tree-dump-times "MIN_EXPR" 3 "phiopt1" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump-not "if " "phiopt1" } } */ /* { dg-final { scan-tree-dump-not "if " "phiopt1" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump-times "MAX_EXPR" 3 "phiopt2" } } */
/* { dg-final { scan-tree-dump-times "MIN_EXPR" 3 "phiopt2" } } */
/* { dg-final { scan-tree-dump-not "if " "phiopt2" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O2 -Warray-bounds -fdump-tree-phiopt1" } */ /* { dg-options "-O2 -Warray-bounds -fdump-tree-phiopt2" } */
void void
h (const void *p, unsigned n) h (const void *p, unsigned n)
...@@ -19,4 +19,4 @@ h (const void *p, unsigned n) ...@@ -19,4 +19,4 @@ h (const void *p, unsigned n)
} }
} }
/* { dg-final { scan-tree-dump "MIN_EXPR" "phiopt1" } } */ /* { dg-final { scan-tree-dump "MIN_EXPR" "phiopt2" } } */
...@@ -3,14 +3,14 @@ ...@@ -3,14 +3,14 @@
line 11, which is very confusing. Make sure we print out a note to line 11, which is very confusing. Make sure we print out a note to
make it less confusing. (not xfailed alternative) make it less confusing. (not xfailed alternative)
But it is of course ok if we warn in bar about uninitialized use But it is of course ok if we warn in bar about uninitialized use
of j. (xfailed alternative) */ of j. (not xfailed alternative) */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O1 -Wuninitialized" } */ /* { dg-options "-O1 -Wuninitialized" } */
inline int inline int
foo (int i) foo (int i)
{ {
if (i) /* { dg-warning "used uninitialized in this function" } */ if (i) /* { dg-warning "used uninitialized in this function" "" } */
return 1; return 1;
return 0; return 0;
} }
...@@ -20,7 +20,7 @@ void baz (void); ...@@ -20,7 +20,7 @@ void baz (void);
void void
bar (void) bar (void)
{ {
int j; /* { dg-message "note: 'j' was declared here" } */ int j; /* { dg-message "note: 'j' was declared here" "" } */
for (; foo (j); ++j) /* { dg-warning "'j' is used uninitialized" "" { xfail *-*-* } } */ for (; foo (j); ++j) /* { dg-warning "'j' is used uninitialized" "" { xfail *-*-* } } */
baz (); baz ();
} }
...@@ -6104,11 +6104,19 @@ gimple_empty_block_p (basic_block bb) ...@@ -6104,11 +6104,19 @@ gimple_empty_block_p (basic_block bb)
gimple_stmt_iterator gsi = gsi_after_labels (bb); gimple_stmt_iterator gsi = gsi_after_labels (bb);
if (phi_nodes (bb)) if (phi_nodes (bb))
return false; return false;
if (gsi_end_p (gsi)) while (!gsi_end_p (gsi))
return true; {
if (is_gimple_debug (gsi_stmt (gsi))) gimple *stmt = gsi_stmt (gsi);
gsi_next_nondebug (&gsi); if (is_gimple_debug (stmt))
return gsi_end_p (gsi); ;
else if (gimple_code (stmt) == GIMPLE_NOP
|| gimple_code (stmt) == GIMPLE_PREDICT)
;
else
return false;
gsi_next (&gsi);
}
return true;
} }
......
...@@ -47,7 +47,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -47,7 +47,7 @@ along with GCC; see the file COPYING3. If not see
#include "params.h" #include "params.h"
#include "case-cfn-macros.h" #include "case-cfn-macros.h"
static unsigned int tree_ssa_phiopt_worker (bool, bool); static unsigned int tree_ssa_phiopt_worker (bool, bool, bool);
static bool conditional_replacement (basic_block, basic_block, static bool conditional_replacement (basic_block, basic_block,
edge, edge, gphi *, tree, tree); edge, edge, gphi *, tree, tree);
static gphi *factor_out_conditional_conversion (edge, edge, gphi *, tree, tree, static gphi *factor_out_conditional_conversion (edge, edge, gphi *, tree, tree,
...@@ -119,7 +119,7 @@ tree_ssa_cs_elim (void) ...@@ -119,7 +119,7 @@ tree_ssa_cs_elim (void)
An interfacing issue of find_data_references_in_bb. */ An interfacing issue of find_data_references_in_bb. */
loop_optimizer_init (LOOPS_NORMAL); loop_optimizer_init (LOOPS_NORMAL);
scev_initialize (); scev_initialize ();
todo = tree_ssa_phiopt_worker (true, false); todo = tree_ssa_phiopt_worker (true, false, false);
scev_finalize (); scev_finalize ();
loop_optimizer_finalize (); loop_optimizer_finalize ();
return todo; return todo;
...@@ -159,7 +159,7 @@ single_non_singleton_phi_for_edges (gimple_seq seq, edge e0, edge e1) ...@@ -159,7 +159,7 @@ single_non_singleton_phi_for_edges (gimple_seq seq, edge e0, edge e1)
DO_HOIST_LOADS is true when we want to hoist adjacent loads out DO_HOIST_LOADS is true when we want to hoist adjacent loads out
of diamond control flow patterns, false otherwise. */ of diamond control flow patterns, false otherwise. */
static unsigned int static unsigned int
tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads) tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p)
{ {
basic_block bb; basic_block bb;
basic_block *bb_order; basic_block *bb_order;
...@@ -289,18 +289,19 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads) ...@@ -289,18 +289,19 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads)
/* Value replacement can work with more than one PHI /* Value replacement can work with more than one PHI
so try that first. */ so try that first. */
for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi)) if (!early_p)
{ for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi))
phi = as_a <gphi *> (gsi_stmt (gsi)); {
arg0 = gimple_phi_arg_def (phi, e1->dest_idx); phi = as_a <gphi *> (gsi_stmt (gsi));
arg1 = gimple_phi_arg_def (phi, e2->dest_idx); arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1) == 2) arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
{ if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1) == 2)
candorest = false; {
cfgchanged = true; candorest = false;
break; cfgchanged = true;
} break;
} }
}
if (!candorest) if (!candorest)
continue; continue;
...@@ -331,12 +332,14 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads) ...@@ -331,12 +332,14 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads)
} }
/* Do the replacement of conditional if it can be done. */ /* Do the replacement of conditional if it can be done. */
if (conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) if (!early_p
&& conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
cfgchanged = true; cfgchanged = true;
else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
cfgchanged = true; cfgchanged = true;
else if (cond_removal_in_popcount_pattern (bb, bb1, e1, e2, else if (!early_p
phi, arg0, arg1)) && cond_removal_in_popcount_pattern (bb, bb1, e1, e2,
phi, arg0, arg1))
cfgchanged = true; cfgchanged = true;
else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
cfgchanged = true; cfgchanged = true;
...@@ -913,7 +916,9 @@ value_replacement (basic_block cond_bb, basic_block middle_bb, ...@@ -913,7 +916,9 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
gsi_next_nondebug (&gsi); gsi_next_nondebug (&gsi);
if (!is_gimple_assign (stmt)) if (!is_gimple_assign (stmt))
{ {
emtpy_or_with_defined_p = false; if (gimple_code (stmt) != GIMPLE_PREDICT
&& gimple_code (stmt) != GIMPLE_NOP)
emtpy_or_with_defined_p = false;
continue; continue;
} }
/* Now try to adjust arg0 or arg1 according to the computation /* Now try to adjust arg0 or arg1 according to the computation
...@@ -2794,17 +2799,26 @@ class pass_phiopt : public gimple_opt_pass ...@@ -2794,17 +2799,26 @@ class pass_phiopt : public gimple_opt_pass
{ {
public: public:
pass_phiopt (gcc::context *ctxt) pass_phiopt (gcc::context *ctxt)
: gimple_opt_pass (pass_data_phiopt, ctxt) : gimple_opt_pass (pass_data_phiopt, ctxt), early_p (false)
{} {}
/* opt_pass methods: */ /* opt_pass methods: */
opt_pass * clone () { return new pass_phiopt (m_ctxt); } opt_pass * clone () { return new pass_phiopt (m_ctxt); }
void set_pass_param (unsigned n, bool param)
{
gcc_assert (n == 0);
early_p = param;
}
virtual bool gate (function *) { return flag_ssa_phiopt; } virtual bool gate (function *) { return flag_ssa_phiopt; }
virtual unsigned int execute (function *) virtual unsigned int execute (function *)
{ {
return tree_ssa_phiopt_worker (false, gate_hoist_loads ()); return tree_ssa_phiopt_worker (false,
!early_p ? gate_hoist_loads () : false,
early_p);
} }
private:
bool early_p;
}; // class pass_phiopt }; // class pass_phiopt
} // anon namespace } // anon namespace
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment