On Mon, 22 Oct 2018, Richard Biener wrote:

> On Wed, 29 Aug 2018, Richard Biener wrote:
> 
> > On Wed, 29 Aug 2018, Jeff Law wrote:
> > 
> > > On 08/29/2018 04:56 AM, Richard Biener wrote:
> > > > 
> > > > In response to PR87105 I dusted off an old patch that adds an early
> > > > phiopt pass.  Recognizing we run phiopt twice with not many passes
> > > > in between early in post-IPA optimizations this patch moves the
> > > > first of said to the early pipeline.
> > > > 
> > > > The main motivation is to do things like MIN/MAX_EXPR early to
> > > > avoid jump threading mess up the CFG (the case with PR87105).
> > > > I realize theres early backward threading before the new early
> > > > phiopt pass but that doesn't seem to do anything useful there (yet).
> > > > I think it makes sense to push that later anyways.
> > > > 
> > > > Now, early phiopt is quite confused about predict stmts still
> > > > being present and turning conditional BBs into diamonds which it
> > > > cannot handle.  I've fixed at least stray such stmts in the BBs
> > > > that are interesting.  Note this may hide fallout which would otherwise
> > > > be visible in the testsuite (there's no flag to avoid
> > > > generating the predictors - they are emitted directly by the frontends,
> > > > maybe we could drop them with -fno[-guess]-branch-probabilities at
> > > > gimplification time?).
> > > > 
> > > > There's also an effect on ifcombine which, when preceeded by phiopt,
> > > > can miss cases because phiopt may value-replace some condition.
> > > > 
> > > > The patch contains adjustments to testcases where there's no harm done
> > > > in the end and leaves those FAILing where we would need to do sth.
> > > > 
> > > > In the end it's regular pass-ordering issues but our testsuite very
> > > > often ties our hands when re-ordering passes because of them.
> > > > 
> > > > One option would be to distinguish early from late phiopt and for
> > > > example avoid value-replacement - like just do MIN/MAX recognition
> > > > for the vectorizer.
> > > > 
> > > > Any comments?
> > > > 
> > > > Some detailed notes on the remaining FAILs below.
> > > [ ... ]
> > > I didn't see anything in the testsuite fallout that gave me significant
> > > concern.  If your judgment is that we're better off running it earlier,
> > > then let's do it.
> > 
> > I guess so.  I'll add an early variant anyway since we don't want to
> > do adjacent load hoisting early.  I'll see how difficult it is to handle
> > ifcombine merging with straight-line code or catch those cases elsewhere.
> 
> So I'm finally returning to this...
> 
> I failed to find a sequence of VRP (jump threading), ifcombine and phiopt
> that avoids regressions (well, the current order works of course).  So
> instead of moving the first phiopt pass I am now _adding_ a phiopt
> pass early doing _only_ min/max/abs replacement.  Those are wrecked
> by jump-threading if they happen in sequences with some common operands.
> 
> Thus the following patch is now in bootstrap & regtest on 
> x86_64-unknown-linux-gnu.
> 
> If that goes well I plan to install the patch after digging out
> the relevant two-to-three PRs and adding testcases for them.

The following is what I have applied.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

Richard.

>From 83f89c82650bdfa057bde3ef1a236338a8cdd848 Mon Sep 17 00:00:00 2001
From: Richard Guenther <rguent...@suse.de>
Date: Tue, 28 Aug 2018 12:53:53 +0200
Subject: [PATCH] early-phiopt

FAIL: g++.dg/predict-loop-exit-2.C -std=gnu++98  scan-tree-dump-times profile_es
timate "loop exit heuristics:" 2

phiopt value-replaces the last "exit" test in

  <bb 4>:
  _5 = foo ();
  if (_5 != 0)
    goto <bb 7>;
  else
    goto <bb 5>;

  <bb 5>:
  g.0_7 = g;
  if (g.0_7 <= 9)
    goto <bb 7>;
  else
    goto <bb 6>;

  <bb 6>:

  <bb 7>:
  # iftmp.3_1 = PHI <1(5), 0(6), 1(4)>
  if (iftmp.3_1 != 0)
    goto <bb 3>;
  else
    goto <bb 8>;

  <bb 8>:
  return;

to look like

  <bb 5>:
  g.0_7 = g;
  _6 = g.0_7 <= 9;

  <bb 6>:
  # iftmp.3_1 = PHI <_6(5), 1(4)>
  if (iftmp.3_1 != 0)
    goto <bb 3>;

which confuses whatever the testcase was supposed to check (there is only
one loop exit).

FAIL: gcc.dg/tree-ssa/ssa-pre-32.c scan-tree-dump pre "# prephitmp_[0-9]+ = PHI 
<[xy]_[0-9]+\\\\(D\\\\)[^,]*, [xy]_[0-9]+\\\\(D\\\\)"

phiopt optimizes

   <bb 2> :
   if (b_5(D) != 0)
     goto <bb 4>; [INV]
   else
     goto <bb 3>; [INV]

   <bb 3> :

   <bb 4> :
   # iftmp.0_3 = PHI <4294967295(2), 0(3)>
   _1 = iftmp.0_3 & x_8(D);

to

   _9 = (unsigned int) b_5(D);
   _14 = -_9;
   _1 = x_8(D) & _14;

but in the sequence with two same conditions but opposite bits
nothing optimizes this further back to b_5(D) ? x_6(D) : y_7(D).

FAIL: gcc.dg/tree-ssa/ssa-ifcombine-7.c scan-tree-dump ifcombine " > "
FAIL: gcc.dg/tree-ssa/ssa-ifcombine-ccmp-1.c scan-tree-dump optimized "&"
FAIL: gcc.dg/tree-ssa/ssa-ifcombine-ccmp-4.c scan-tree-dump optimized "&"
FAIL: gcc.dg/tree-ssa/ssa-ifcombine-ccmp-5.c scan-tree-dump-times optimized "&" 
2
  \|" 2

early phiopt value-replaces the inner condition which leaves ifcombine
with no work.

2018-10-23  Richard Biener  <rguent...@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.

diff --git a/gcc/passes.def b/gcc/passes.def
index 7f4b3479a35..24f212c8e31 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -88,6 +88,7 @@ along with GCC; see the file COPYING3.  If not see
          NEXT_PASS (pass_merge_phi);
           NEXT_PASS (pass_dse);
          NEXT_PASS (pass_cd_dce);
+         NEXT_PASS (pass_phiopt, true /* early_p */);
          NEXT_PASS (pass_early_ipa_sra);
          NEXT_PASS (pass_tail_recursion);
          NEXT_PASS (pass_convert_switch);
@@ -208,7 +209,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_copy_prop);
       NEXT_PASS (pass_tree_ifcombine);
       NEXT_PASS (pass_merge_phi);
-      NEXT_PASS (pass_phiopt);
+      NEXT_PASS (pass_phiopt, false /* early_p */);
       NEXT_PASS (pass_tail_recursion);
       NEXT_PASS (pass_ch);
       NEXT_PASS (pass_lower_complex);
@@ -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_dce);
       NEXT_PASS (pass_forwprop);
-      NEXT_PASS (pass_phiopt);
+      NEXT_PASS (pass_phiopt, false /* early_p */);
       NEXT_PASS (pass_ccp, true /* nonzero_p */);
       /* After CCP we rewrite no longer addressed locals into SSA
         form if possible.  */
@@ -328,7 +329,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_dse);
       NEXT_PASS (pass_cd_dce);
       NEXT_PASS (pass_forwprop);
-      NEXT_PASS (pass_phiopt);
+      NEXT_PASS (pass_phiopt, false /* early_p */);
       NEXT_PASS (pass_fold_builtins);
       NEXT_PASS (pass_optimize_widening_mul);
       NEXT_PASS (pass_store_merging);
diff --git a/gcc/testsuite/g++.dg/tree-ssa/phiopt-1.C 
b/gcc/testsuite/g++.dg/tree-ssa/phiopt-1.C
new file mode 100644
index 00000000000..83d976a7ac9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/phiopt-1.C
@@ -0,0 +1,94 @@
+// { 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" } }
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr21463.C 
b/gcc/testsuite/g++.dg/tree-ssa/pr21463.C
index 0aed8482e6f..45d83415648 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr21463.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr21463.C
@@ -1,5 +1,5 @@
 /* { 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)
 { return a<b ? b : a; }
@@ -15,5 +15,5 @@ template<class T> struct foo_t {
 
 template struct foo_t<int>;
 
-/* { dg-final { scan-tree-dump-times "MIN_EXPR" 2 "phiopt1" } } */
-/* { dg-final { scan-tree-dump-times "MAX_EXPR" 2 "phiopt1" } } */
+/* { dg-final { scan-tree-dump-times "MIN_EXPR" 2 "phiopt2" } } */
+/* { dg-final { scan-tree-dump-times "MAX_EXPR" 2 "phiopt2" } } */
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr30738.C 
b/gcc/testsuite/g++.dg/tree-ssa/pr30738.C
index 84cfdd98cc1..1c989bde741 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr30738.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr30738.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-phiopt1" } */
+/* { dg-options "-O -fdump-tree-phiopt2" } */
 
 template <class T>
 static inline const T&
@@ -13,4 +13,4 @@ int test_min_ref (int x, int y)
   return min_ref (x, y);
 }
 
-/* { dg-final { scan-tree-dump "MIN_EXPR" "phiopt1" } } */
+/* { dg-final { scan-tree-dump "MIN_EXPR" "phiopt2" } } */
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr57380.C 
b/gcc/testsuite/g++.dg/tree-ssa/pr57380.C
index fce6279eeb5..864129bfa69 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr57380.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr57380.C
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-phiopt1" } */
+/* { dg-options "-O2 -fdump-tree-phiopt2" } */
 /* { dg-add-options bind_pic_locally } */
 
 struct my_array {
@@ -18,4 +18,4 @@ int f(my_array a, my_array b) {
     return res;
 }
 
-/* { dg-final { scan-tree-dump "MAX_EXPR" "phiopt1" } } */
+/* { dg-final { scan-tree-dump "MAX_EXPR" "phiopt2" } } */
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr86544.C 
b/gcc/testsuite/g++.dg/tree-ssa/pr86544.C
index 8a900896e50..fd844b48deb 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr86544.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr86544.C
@@ -1,5 +1,5 @@
 /* { 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 c = 0;
@@ -12,4 +12,4 @@ int PopCount (long b) {
 }
 
 /* { 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" } } */
diff --git a/gcc/testsuite/g++.dg/vect/slp-pr87105.cc 
b/gcc/testsuite/g++.dg/vect/slp-pr87105.cc
new file mode 100644
index 00000000000..1023d915201
--- /dev/null
+++ b/gcc/testsuite/g++.dg/vect/slp-pr87105.cc
@@ -0,0 +1,104 @@
+// { 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 *-*-* } } }
diff --git a/gcc/testsuite/gcc.dg/pr24574.c b/gcc/testsuite/gcc.dg/pr24574.c
index db0d8692a76..93ce0f68429 100644
--- a/gcc/testsuite/gcc.dg/pr24574.c
+++ b/gcc/testsuite/gcc.dg/pr24574.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-phiopt1" } */
+/* { dg-options "-O -fdump-tree-phiopt2" } */
 
 int f0(int i)
 {
@@ -33,4 +33,4 @@ int f5(int i)
 
 /* We should if-convert all functions to carry out the operation
    unconditionally.  */
-/* { dg-final { scan-tree-dump-not "= PHI" "phiopt1" } } */
+/* { dg-final { scan-tree-dump-not "= PHI" "phiopt2" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040514-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/20040514-1.c
index 91fa65d070b..364ce6a6966 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/20040514-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/20040514-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O1 -fdump-tree-phiopt1-details" } */
+/* { dg-options "-O1 -fdump-tree-phiopt2-details" } */
 
 int t( int i)
 {
@@ -15,4 +15,4 @@ end:
 }
 
 /* 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"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040518-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/20040518-1.c
index f80a74a14ea..a093c77d913 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/20040518-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/20040518-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O1 -fdump-tree-phiopt1-details" } */
+/* { dg-options "-O1 -fdump-tree-phiopt2-details" } */
 int f(int a, int b)
 {
    int c = b;
@@ -9,4 +9,4 @@ int f(int a, int b)
 }
 
 /* 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"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-12.c 
b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-12.c
index f00d0fcc474..a221b762e1d 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-12.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-12.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-phiopt1" } */
+/* { dg-options "-O -fdump-tree-phiopt2" } */
 
 int f(int a, int b, int c) {
   if (c > 5) return c;
@@ -19,4 +19,4 @@ unsigned m(unsigned a, unsigned b) {
     return a & b;
 }
 
-/* { dg-final { scan-tree-dump-times "goto" 2 "phiopt1" } } */
+/* { dg-final { scan-tree-dump-times "goto" 2 "phiopt2" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-5.c 
b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-5.c
index 31c0fc1f2fb..5a00f3ddf8c 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-5.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-5.c
@@ -1,5 +1,5 @@
 /* { 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)
 {
@@ -16,8 +16,11 @@ float repl1 (float varx)
    varx_4 = MIN_EXPR <1.0e+0, varx_2>;
    varx_5 = MAX_EXPR <varx_4, 0.0>;  */  
 
-/* { dg-final { scan-tree-dump "varx.*MIN_EXPR.*1\\.0" "phiopt1"} } */
-/* { dg-final { scan-tree-dump "varx.*MAX_EXPR.*0\\.0" "phiopt1"} } */
+/* phiopt1 confused by predictors.  */
+/* { 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)
 {
@@ -34,8 +37,11 @@ float repl2 (float vary)
    vary_4 = MAX_EXPR <0.0, vary_2>;
    vary_5 = MIN_EXPR <vary_4, 1.0e+0>;  */
 
-/* { dg-final { scan-tree-dump "vary.*MAX_EXPR.*0\\.0" "phiopt1"} } */
-/* { dg-final { scan-tree-dump "vary.*MIN_EXPR.*1\\.0" "phiopt1"} } */
+/* phiopt1 confused by predictors.  */
+/* { 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)
 {
@@ -54,5 +60,7 @@ float repl3 (float varz, float vara, float varb)
 <L1>:;
   vara_6 = MAX_EXPR <varb_5, varz_2>;  */
 
-/* { dg-final { scan-tree-dump "if .*varz" "phiopt1"} } */
-/* { dg-final { scan-tree-dump "vara.*MAX_EXPR" "phiopt1"} } */
+/* phiopt1 confused by predictors.  */
+/* { 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"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-6.c 
b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-6.c
index 780530d1e42..a5020c05867 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-6.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-6.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-phiopt1" } */
+/* { dg-options "-O -fdump-tree-phiopt2" } */
 
 struct C { int i; };
 int *g(struct C *p)
@@ -9,4 +9,4 @@ int *g(struct C *p)
   return (int *)0;
 }
 
-/* { dg-final { scan-tree-dump-not "if" "phiopt1" } } */
+/* { dg-final { scan-tree-dump-not "if" "phiopt2" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-8.c 
b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-8.c
index e3b2771dbb2..98c596b6aa4 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-8.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-8.c
@@ -1,5 +1,5 @@
 /* { 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 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
    two phis.  Note this is fixed with
    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-not "PHI" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/popcount3.c 
b/gcc/testsuite/gcc.dg/tree-ssa/popcount3.c
index 8a900896e50..fd844b48deb 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/popcount3.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/popcount3.c
@@ -1,5 +1,5 @@
 /* { 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 c = 0;
@@ -12,4 +12,4 @@ int PopCount (long b) {
 }
 
 /* { 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" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr45397.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr45397.c
index af75a75b1e2..8eacb518777 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr45397.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr45397.c
@@ -1,5 +1,5 @@
 /* { 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)
 {
@@ -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
    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-times "MAX_EXPR" 3 "phiopt1" } } */
-/* { dg-final { scan-tree-dump-times "MIN_EXPR" 3 "phiopt1" } } */
-/* { dg-final { scan-tree-dump-not "if " "phiopt1" } } */
+/* { dg-final { scan-tree-dump-times "MAX_EXPR" 3 "phiopt1" { xfail *-*-* } } 
} */
+/* { dg-final { scan-tree-dump-times "MIN_EXPR" 3 "phiopt1" { xfail *-*-* } } 
} */
+/* { 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" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr84859.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr84859.c
index 577b561545d..a2c98866e6c 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr84859.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr84859.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -Warray-bounds -fdump-tree-phiopt1" } */
+/* { dg-options "-O2 -Warray-bounds -fdump-tree-phiopt2" } */
 
 void
 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" } } */
diff --git a/gcc/testsuite/gcc.dg/uninit-15.c b/gcc/testsuite/gcc.dg/uninit-15.c
index 6154f4b638a..67aac41d49e 100644
--- a/gcc/testsuite/gcc.dg/uninit-15.c
+++ b/gcc/testsuite/gcc.dg/uninit-15.c
@@ -3,14 +3,14 @@
    line 11, which is very confusing.  Make sure we print out a note to
    make it less confusing.  (not xfailed alternative)
    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-options "-O1 -Wuninitialized" } */
 
 inline int
 foo (int i)
 {
-  if (i) /* { dg-warning "used uninitialized in this function" } */
+  if (i) /* { dg-warning "used uninitialized in this function" "" } */
     return 1;
   return 0;
 }
@@ -20,7 +20,7 @@ void baz (void);
 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 
*-*-* } } */
     baz ();
 }
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index d30e4aca773..5f334ca7927 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -6104,11 +6104,19 @@ gimple_empty_block_p (basic_block bb)
   gimple_stmt_iterator gsi = gsi_after_labels (bb);
   if (phi_nodes (bb))
     return false;
-  if (gsi_end_p (gsi))
-    return true;
-  if (is_gimple_debug (gsi_stmt (gsi)))
-    gsi_next_nondebug (&gsi);
-  return gsi_end_p (gsi);
+  while (!gsi_end_p (gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      if (is_gimple_debug (stmt))
+       ;
+      else if (gimple_code (stmt) == GIMPLE_NOP
+              || gimple_code (stmt) == GIMPLE_PREDICT)
+       ;
+      else
+       return false;
+      gsi_next (&gsi);
+    }
+  return true;
 }
 
 
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
index 1667bad873b..07845101b86 100644
--- a/gcc/tree-ssa-phiopt.c
+++ b/gcc/tree-ssa-phiopt.c
@@ -47,7 +47,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.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,
                                     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)
      An interfacing issue of find_data_references_in_bb.  */
   loop_optimizer_init (LOOPS_NORMAL);
   scev_initialize ();
-  todo = tree_ssa_phiopt_worker (true, false);
+  todo = tree_ssa_phiopt_worker (true, false, false);
   scev_finalize ();
   loop_optimizer_finalize ();
   return todo;
@@ -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
    of diamond control flow patterns, false otherwise.  */
 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_order;
@@ -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
             so try that first. */
-         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);
-             arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
-             if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1) == 2)
-               {
-                 candorest = false;
-                 cfgchanged = true;
-                 break;
-               }
-           }
+         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);
+               arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
+               if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1) == 2)
+                 {
+                   candorest = false;
+                   cfgchanged = true;
+                   break;
+                 }
+             }
 
          if (!candorest)
            continue;
@@ -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.  */
-         if (conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
+         if (!early_p
+             && conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
            cfgchanged = true;
          else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
            cfgchanged = true;
-         else if (cond_removal_in_popcount_pattern (bb, bb1, e1, e2,
-                                                    phi, arg0, arg1))
+         else if (!early_p
+                  && cond_removal_in_popcount_pattern (bb, bb1, e1, e2,
+                                                       phi, arg0, arg1))
            cfgchanged = true;
          else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
            cfgchanged = true;
@@ -913,7 +916,9 @@ value_replacement (basic_block cond_bb, basic_block 
middle_bb,
       gsi_next_nondebug (&gsi);
       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;
        }
       /* Now try to adjust arg0 or arg1 according to the computation
@@ -2794,17 +2799,26 @@ class pass_phiopt : public gimple_opt_pass
 {
 public:
   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 * 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 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
 
 } // anon namespace

Reply via email to