]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Backwards jump threader rewrite with ranger.
authorAldy Hernandez <aldyh@redhat.com>
Tue, 15 Jun 2021 10:32:51 +0000 (12:32 +0200)
committerAldy Hernandez <aldyh@redhat.com>
Thu, 29 Jul 2021 06:24:50 +0000 (08:24 +0200)
This is a rewrite of the backwards threader with a ranger based solver.

The code is divided into two parts: the path solver in
gimple-range-path.*, and the path discovery bits in
tree-ssa-threadbackward.c.

The legacy code is still available with --param=threader-mode=legacy,
but will be removed shortly after.

gcc/ChangeLog:

* Makefile.in (tree-ssa-loop-im.o-warn): New.
* flag-types.h (enum threader_mode): New.
* params.opt: Add entry for --param=threader-mode.
* tree-ssa-threadbackward.c (THREADER_ITERATIVE_MODE): New.
(class back_threader): New.
(back_threader::back_threader): New.
(back_threader::~back_threader): New.
(back_threader::maybe_register_path): New.
(back_threader::find_taken_edge): New.
(back_threader::find_taken_edge_switch): New.
(back_threader::find_taken_edge_cond): New.
(back_threader::resolve_def): New.
(back_threader::resolve_phi): New.
(back_threader::find_paths_to_names): New.
(back_threader::find_paths): New.
(dump_path): New.
(debug): New.
(thread_jumps::find_jump_threads_backwards): Call ranger threader.
(thread_jumps::find_jump_threads_backwards_with_ranger): New.
(pass_thread_jumps::execute): Abstract out code...
(try_thread_blocks): ...here.
* tree-ssa-threadedge.c (jump_threader::thread_outgoing_edges):
Abstract out threading candidate code to...
(single_succ_to_potentially_threadable_block): ...here.
* tree-ssa-threadedge.h (single_succ_to_potentially_threadable_block):
New.
* tree-ssa-threadupdate.c (register_jump_thread): Return boolean.
* tree-ssa-threadupdate.h (class jump_thread_path_registry):
Return bool from register_jump_thread.

libgomp/ChangeLog:

* testsuite/libgomp.graphite/force-parallel-4.c: Adjust for
threader.
* testsuite/libgomp.graphite/force-parallel-8.c: Same.

gcc/testsuite/ChangeLog:

* g++.dg/debug/dwarf2/deallocator.C: Adjust for threader.
* gcc.c-torture/compile/pr83510.c: Same.
* dg.dg/analyzer/pr94851-2.c: Same.
* gcc.dg/loop-unswitch-2.c: Same.
* gcc.dg/old-style-asm-1.c: Same.
* gcc.dg/pr68317.c: Same.
* gcc.dg/pr97567-2.c: Same.
* gcc.dg/predict-9.c: Same.
* gcc.dg/shrink-wrap-loop.c: Same.
* gcc.dg/sibcall-1.c: Same.
* gcc.dg/tree-ssa/builtin-sprintf-3.c: Same.
* gcc.dg/tree-ssa/pr21001.c: Same.
* gcc.dg/tree-ssa/pr21294.c: Same.
* gcc.dg/tree-ssa/pr21417.c: Same.
* gcc.dg/tree-ssa/pr21458-2.c: Same.
* gcc.dg/tree-ssa/pr21563.c: Same.
* gcc.dg/tree-ssa/pr49039.c: Same.
* gcc.dg/tree-ssa/pr61839_1.c: Same.
* gcc.dg/tree-ssa/pr61839_3.c: Same.
* gcc.dg/tree-ssa/pr77445-2.c: Same.
* gcc.dg/tree-ssa/split-path-4.c: Same.
* gcc.dg/tree-ssa/ssa-dom-thread-11.c: Same.
* gcc.dg/tree-ssa/ssa-dom-thread-12.c: Same.
* gcc.dg/tree-ssa/ssa-dom-thread-14.c: Same.
* gcc.dg/tree-ssa/ssa-dom-thread-18.c: Same.
* gcc.dg/tree-ssa/ssa-dom-thread-6.c: Same.
* gcc.dg/tree-ssa/ssa-dom-thread-7.c: Same.
* gcc.dg/tree-ssa/ssa-fre-48.c: Same.
* gcc.dg/tree-ssa/ssa-thread-11.c: Same.
* gcc.dg/tree-ssa/ssa-thread-12.c: Same.
* gcc.dg/tree-ssa/ssa-thread-14.c: Same.
* gcc.dg/tree-ssa/vrp02.c: Same.
* gcc.dg/tree-ssa/vrp03.c: Same.
* gcc.dg/tree-ssa/vrp05.c: Same.
* gcc.dg/tree-ssa/vrp06.c: Same.
* gcc.dg/tree-ssa/vrp07.c: Same.
* gcc.dg/tree-ssa/vrp09.c: Same.
* gcc.dg/tree-ssa/vrp19.c: Same.
* gcc.dg/tree-ssa/vrp20.c: Same.
* gcc.dg/tree-ssa/vrp33.c: Same.
* gcc.dg/uninit-pred-9_b.c: Same.
* gcc.dg/uninit-pr61112.c: Same.
* gcc.dg/vect/bb-slp-16.c: Same.
* gcc.target/i386/avx2-vect-aggressive.c: Same.
* gcc.dg/tree-ssa/ranger-threader-1.c: New test.
* gcc.dg/tree-ssa/ranger-threader-2.c: New test.
* gcc.dg/tree-ssa/ranger-threader-3.c: New test.
* gcc.dg/tree-ssa/ranger-threader-4.c: New test.
* gcc.dg/tree-ssa/ranger-threader-5.c: New test.

58 files changed:
gcc/flag-types.h
gcc/params.opt
gcc/testsuite/g++.dg/debug/dwarf2/deallocator.C
gcc/testsuite/gcc.c-torture/compile/pr83510.c
gcc/testsuite/gcc.dg/analyzer/pr94851-2.c
gcc/testsuite/gcc.dg/loop-unswitch-2.c
gcc/testsuite/gcc.dg/old-style-asm-1.c
gcc/testsuite/gcc.dg/pr68317.c
gcc/testsuite/gcc.dg/pr97567-2.c
gcc/testsuite/gcc.dg/predict-9.c
gcc/testsuite/gcc.dg/shrink-wrap-loop.c
gcc/testsuite/gcc.dg/sibcall-1.c
gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-3.c
gcc/testsuite/gcc.dg/tree-ssa/pr21001.c
gcc/testsuite/gcc.dg/tree-ssa/pr21294.c
gcc/testsuite/gcc.dg/tree-ssa/pr21417.c
gcc/testsuite/gcc.dg/tree-ssa/pr21458-2.c
gcc/testsuite/gcc.dg/tree-ssa/pr21563.c
gcc/testsuite/gcc.dg/tree-ssa/pr49039.c
gcc/testsuite/gcc.dg/tree-ssa/pr61839_1.c
gcc/testsuite/gcc.dg/tree-ssa/pr61839_3.c
gcc/testsuite/gcc.dg/tree-ssa/pr77445-2.c
gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/split-path-4.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-11.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-12.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-14.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-18.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-6.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-48.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-11.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-12.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-14.c
gcc/testsuite/gcc.dg/tree-ssa/vrp02.c
gcc/testsuite/gcc.dg/tree-ssa/vrp03.c
gcc/testsuite/gcc.dg/tree-ssa/vrp05.c
gcc/testsuite/gcc.dg/tree-ssa/vrp06.c
gcc/testsuite/gcc.dg/tree-ssa/vrp07.c
gcc/testsuite/gcc.dg/tree-ssa/vrp09.c
gcc/testsuite/gcc.dg/tree-ssa/vrp19.c
gcc/testsuite/gcc.dg/tree-ssa/vrp20.c
gcc/testsuite/gcc.dg/tree-ssa/vrp33.c
gcc/testsuite/gcc.dg/uninit-pr61112.c
gcc/testsuite/gcc.dg/uninit-pred-9_b.c
gcc/testsuite/gcc.dg/vect/bb-slp-16.c
gcc/testsuite/gcc.target/i386/avx2-vect-aggressive.c
gcc/tree-ssa-threadbackward.c
gcc/tree-ssa-threadedge.c
gcc/tree-ssa-threadedge.h
gcc/tree-ssa-threadupdate.c
gcc/tree-ssa-threadupdate.h
libgomp/testsuite/libgomp.graphite/force-parallel-4.c
libgomp/testsuite/libgomp.graphite/force-parallel-8.c

index e43d1de490df7a2142dbbdb16fd348a4841a5dbb..e39673f6716aad0367633116617fb55f45ef0cac 100644 (file)
@@ -454,6 +454,13 @@ enum evrp_mode
   EVRP_MODE_RVRP_DEBUG = EVRP_MODE_RVRP_ONLY | EVRP_MODE_DEBUG
 };
 
+/* Backwards threader mode.  */
+enum threader_mode
+{
+  THREADER_MODE_LEGACY = 0,
+  THREADER_MODE_RANGER = 1
+};
+
 /* Modes of OpenACC 'kernels' constructs handling.  */
 enum openacc_kernels
 {
index 92b003e38cbb18ec6d3570c7c7f717fe42a3d9c5..f1f47b44215aabc75d0465dec8c03171e5ccf630 100644 (file)
@@ -1010,6 +1010,23 @@ Maximum depth of DFS walk used by modref escape analysis.
 Common Joined UInteger Var(param_modref_max_escape_points) Init(256) Param Optimization
 Maximum number of escape points tracked by modref per SSA-name.
 
+-param=threader-iterative=
+Common Joined UInteger Var(param_threader_iterative) Init(0) Param Optimization
+Run backwards threader in iterative mode.
+
+-param=threader-mode=
+Common Joined Var(param_threader_mode) Enum(threader_mode) Init(THREADER_MODE_RANGER) Param Optimization
+--param=threader-mode=[legacy|ranger] Specifies the mode the backwards threader should run in.
+
+Enum
+Name(threader_mode) Type(enum threader_mode) UnknownError(unknown threader mode %qs)
+
+EnumValue
+Enum(threader_mode) String(legacy) Value(THREADER_MODE_LEGACY)
+
+EnumValue
+Enum(threader_mode) String(ranger) Value(THREADER_MODE_RANGER)
+
 -param=tm-max-aggregate-size=
 Common Joined UInteger Var(param_tm_max_aggregate_size) Init(9) Param Optimization
 Size in bytes after which thread-local aggregates should be instrumented with the logging functions instead of save/restore pairs.
index d895e78e608eb28ae74f15f933c548b9ba6e919b..c1d387922ba290d909d9b692f4a165d66f69392c 100644 (file)
@@ -29,7 +29,7 @@ void foo(int i)
          return;
        }
     }
-  if (i)
+  if (i) // Threader makes everything after here disappear.
     {
       t test;
       if (i == 10)
@@ -42,5 +42,4 @@ void foo(int i)
 }
 // { dg-final { scan-assembler "deallocator.C:29" } }
 // { dg-final { scan-assembler "deallocator.C:24" } }
-// { dg-final { scan-assembler "deallocator.C:34" } }
 // { dg-final { scan-assembler "deallocator.C:21" } }
index 907dd80ccd79e4a9792c147e342d50792bb77387..fc932e57f3ae55ab31b8c3cdce9a2a06b21190b6 100644 (file)
@@ -3,6 +3,39 @@
    (PR tree-optimization/83510).  */
 
 /* { dg-options "-Warray-bounds" } */
+/* { dg-xfail-if "" { "*-*-*" } { "-Os" } } */
+
+
+/*  This test is XFAILed because thread1 threads a switch statement
+    such that the various cases have been split into different
+    independent blocks.  One of these blocks exposes an arr[i_27]
+    which is later propagated by VRP to be arr[10].  This is an
+    invalid access, but the array bounds code doesn't know it is an
+    unreachable path.
+
+    However, it is not until dom2 that we "know" that the value of the
+    switch index is such that the path to arr[10] is unreachable.  For
+    that matter, it is not until dom3 that we remove the unreachable
+    path.
+
+
+    See:
+    https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83510
+    https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83312
+
+    It's not until here that ranger "knows" that the path is
+    unreachable:
+
+    thread1
+    vrp1               <-- array bounds checking
+    dce2
+    stdarg
+    cdce
+    cselim
+    copyprop
+    ifcombine
+    mergephi3          <-- too late
+*/
 
 extern int get_flag (void);
 
index b837451b27af1247328194d3cbd2258c70ea2ea2..0acf48810c1f12eb0fcbf91fdf110cebe671c099 100644 (file)
@@ -45,7 +45,7 @@ int pamark(void) {
     if (curbp->b_amark == (AMARK *)NULL)
       curbp->b_amark = p;
     else
-      last->m_next = p; /* { dg-warning "dereference of NULL 'last'" } */
+      last->m_next = p; /* { dg-warning "dereference of NULL 'last'" "deref" { xfail *-*-* } } */
   }
 
   p->m_name = (char)c; /* { dg-bogus "leak of 'p'" "bogus leak" } */
index f8d314e34de28714325646ebe356596ad1cc7dea..0931f6e71c3629ea9fd520688977e45b6e694443 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -funswitch-loops -fdump-tree-unswitch-details" } */
+/* { dg-options "-O2 -funswitch-loops -fdump-tree-unswitch-details -fdisable-tree-thread2 -fdisable-tree-thread3" } */
 
 void foo (float **a, float **b, float *c, int n, int m, int l)
 {
index 8af007795a72302f4f29ae65e32221bb8f268f73..f9406ff0a261ca15ec6645f752dbc579c45b0394 100644 (file)
@@ -1,6 +1,9 @@
 /* PR inline-asm/8832 */
 /* { dg-do compile } */
-/* { dg-options "-O2 -dP" } */
+/* { dg-options "-O2 -dP -fdisable-tree-ethread -fdisable-tree-thread1 -fdisable-tree-thread2 -fdisable-tree-thread3 -fdisable-tree-thread4" } */
+
+/* Note: Threader will duplicate BBs and replace one conditional branch by an
+   unconditional one.  */
 
 /* Verify that GCC doesn't optimize
    old style asm instructions.  */
index 891d12954babfdd4ed37bf417aedbf45c5f546d8..bd053a7522bcbc7dc0ef2ae30d48f51566b5c1ae 100644 (file)
@@ -1,5 +1,7 @@
 /* { dg-do compile } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -fdisable-tree-ethread" } */
+
+/* Note: Threader will collapse loop.  */
 
 typedef int int32_t __attribute__((mode (__SI__)));
 
index dee31c6dc013fb53ccbeb09fb563bf8bcc53589f..c3ead54eaa8eefa409adfa35e4268267f45720ef 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile} */
-/* { dg-options "-O2 -fdump-tree-evrp" } */
+/* { dg-options "-O2 -fdump-tree-evrp -fdisable-tree-ethread" } */
 
 char a[2];
 
index f491c511bd9d6ee558fdc581ec9b517e6596d41e..cb68a218a931cd1b98c85bf25094f73f4668105f 100644 (file)
@@ -1,5 +1,7 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-profile_estimate -fno-finite-loops" } */
+/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-profile_estimate -fno-finite-loops -fdisable-tree-ethread" } */
+
+/* Note: Threader causes removal of for loop.  */
 
 extern int global;
 extern int global2;
index 52dfc2790ed27fe2446a998e25070daf9b24a652..ba872fa23f67b6d9c2def28ddb64ecaa86b78f92 100644 (file)
@@ -1,5 +1,58 @@
 /* { dg-do compile { target { { { i?86-*-* x86_64-*-* } && lp64 } || { arm_thumb2 } } } } */
 /* { dg-options "-O2 -fdump-rtl-pro_and_epilogue"  } */
+// { dg-additional-options "-fdisable-tree-ethread" }
+
+/*
+Our new threader is threading things a bit too early, and causing the
+testcase in gcc.dg/shrink-wrap-loop.c to fail.
+
+  The gist is this BB inside a loop:
+
+  <bb 6> :
+  # p_2 = PHI <p2_6(D)(2), p_12(5)>
+  if (p_2 != 0B)
+    goto <bb 3>; [INV]
+  else
+    goto <bb 7>; [INV]
+
+Our threader can move this check outside of the loop (good).  This is
+done before branch probabilities are calculated and causes the probs
+to be calculated as:
+
+<bb 2> [local count: 216361238]:
+  if (p2_6(D) != 0B)
+    goto <bb 7>; [54.59%]
+  else
+    goto <bb 6>; [45.41%]
+
+Logically this seems correct to me.  A simple check outside of a loop
+should slightly but not overwhelmingly favor a non-zero value.
+
+Interestingly however, the old threader couldn't get this, but the IL
+ended up identical, albeit with different probabilities.  What happens
+is that, because the old code could not thread this, the p2 != 0 check
+would remain inside the loop and probs would be calculated thusly:
+
+  <bb 6> [local count: 1073741824]:
+  # p_2 = PHI <p2_6(D)(2), p_12(5)>
+  if (p_2 != 0B)
+    goto <bb 3>; [94.50%]
+  else
+    goto <bb 7>; [5.50%]
+
+Then when the loop header copying pass ("ch") shuffled things around,
+the IL would end up identical to my early threader code, but with the
+probabilities would remain as 94.5/5.5.
+
+The above discrepancy causes the RTL ifcvt pass to generate different
+code, and by the time we get to the shrink wrapping pass, things look
+sufficiently different such that the legacy code can actually shrink
+wrap, whereas our new code does not.
+
+IMO, if the loop-ch pass moves conditionals outside of a loop, the
+probabilities should be adjusted, but that does mean the shrink wrap
+won't happen for this contrived testcase.
+ */
 
 int foo (int *p1, int *p2);
 
index e8a95513d9e8c8617243a2cd49244680697573a5..367ee4374e16e222ba0270bd20590e70d2028ae4 100644 (file)
@@ -7,6 +7,9 @@
 /* { dg-do run } */
 /* { dg-options "-O2 -foptimize-sibling-calls" } */
 
+/* See note in recurser_void() as to why we disable threading.  */
+/* { dg-additional-options "-fdisable-tree-thread1" } */
+
 /* The option -foptimize-sibling-calls is the default, but serves as
    marker.  Self-recursion tail calls are optimized for all targets,
    regardless of presence of sibcall patterns.  */
@@ -26,6 +29,13 @@ int main ()
 void
 recurser_void (int n)
 {
+  /* In some architectures like ppc64*, jump threading may thread
+     paths such that there are two calls into track(), one for
+     track(0) and one for track(7).  The track(7) call can be
+     transformed into a jump instead of a call, which means that
+     different calls into track() may end up with a different
+     &stackpos.  This is the reason we disable jump threading for this
+     test.  */
   if (n == 0 || n == 7)
     track (n);
 
index fae2a1b73ead288cc2dcb1eb759cfcfa13f0d35b..ec55f2673184e09da425e4eed909c80223003374 100644 (file)
@@ -15,7 +15,7 @@ extern void string_lt_0_fail ();
 extern void string_eq_0_fail ();
 extern void string_gt_0_fail ();
 
-void test_string (char *d, const char *s)
+void test_string_eq_min (char *d, const char *s)
 {
   int n = __builtin_sprintf (d, "%-s", s);
 
@@ -23,13 +23,36 @@ void test_string (char *d, const char *s)
      or INT_MAX.  (This is a white box test based on knowing that
      the optimization computes its own values of the two constants.)  */
   if (n == INT_MIN) string_eq_min_fail ();
+}
+
+void test_string_eq_max (char *d, const char *s)
+{
+  int n = __builtin_sprintf (d, "%-s", s);
+
   if (n == INT_MAX) string_eq_max_fail ();
+}
+
+void test_string_lt_0 (char *d, const char *s)
+{
+  int n = __builtin_sprintf (d, "%-s", s);
 
   /* The return value could be negative when strlen(s) is in excess
      of 4095 (the maximum number of bytes a single directive is required
      to handle).  */
   if (n < 0) string_lt_0_fail ();
+}
+
+void test_string_eq_0 (char *d, const char *s)
+{
+  int n = __builtin_sprintf (d, "%-s", s);
+
   if (n == 0) string_eq_0_fail ();
+}
+
+void test_string_gt_0 (char *d, const char *s)
+{
+  int n = __builtin_sprintf (d, "%-s", s);
+
   if (n > 0) string_gt_0_fail ();
 }
 
index 719360a015f9041ef61225870beaa0271e05bfdc..4ea5f21addf35b31dfeada7ef1f75c20cab49268 100644 (file)
@@ -6,6 +6,7 @@
 
 /* { dg-do compile } */
 /* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1-details" } */
+/* { dg-additional-options "-fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 int
 foo (int a)
index cc7d4cdf3381bf3d356eb9adcda8580cdb95a175..b9edabc62347178830ab7b45b7563d93e72569a9 100644 (file)
@@ -5,6 +5,7 @@
 
 /* { dg-do compile } */
 /* { dg-options "-O2 -fno-tree-dominator-opts -fdisable-tree-evrp -fdump-tree-vrp1-details" } */
+/* { dg-additional-options "-fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 struct f {
   int i;
index 484511978a1023724f6ca6a84cbb765777a598a7..fc14af4e662a0d6aad77f9c45d7eb0474c0862cc 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-thread4-details" } */
+/* { dg-options "-O2 -fdisable-tree-thread3 -fdump-tree-thread4-details" } */
 
 struct tree_common 
 { 
index 2aee42f4c05f683dca2202d09993c8ac8ec682fa..f8d7353fc0e0e108c41795077a1ed7ed8db9d8f1 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-evrp-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details -fdisable-tree-ethread" } */
 
 extern void g (void);
 extern void bar (int);
index 9c67a3acb46a75ca8558a487cd8edc885d0ba2dd..72dce83ce37abd2331fa1a93a22bea1142532304 100644 (file)
@@ -2,7 +2,7 @@
    Make sure VRP folds the second "if" statement.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-dominator-opts -fdisable-tree-evrp -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-dominator-opts -fdisable-tree-evrp -fdump-tree-vrp1-details -fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 int
 foo (int a)
index 4bc0a8175a0f7f18e07ffaf5d8239e56c111382e..a2044d012cc69d5e60591f7a55b7d88e8caee996 100644 (file)
@@ -1,6 +1,6 @@
 /* PR tree-optimization/49039 */
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 extern void bar (void);
 
index d44c7dc188219b227a9e3ec7725ad288bf23e10e..ddc53fbfbcc0e7c892312715ac928fa816fda2ca 100644 (file)
@@ -1,6 +1,6 @@
 /* PR tree-optimization/61839.  */
 /* { dg-do run } */
-/* { dg-options "-O2 -fdump-tree-vrp1 -fdisable-tree-evrp -fdump-tree-optimized" } */
+/* { dg-options "-O2 -fdump-tree-vrp1 -fdisable-tree-evrp -fdump-tree-optimized -fdisable-tree-ethread -fdisable-tree-thread1" } */
 /* { dg-require-effective-target int32plus } */
 
 __attribute__ ((noinline))
index 5ceb0738bded19adfcbd5ba6e02c8060f7818804..cc322d6e703ac6c2505175e00460d1f5c6af6782 100644 (file)
@@ -1,6 +1,6 @@
 /* PR tree-optimization/61839.  */
 /* { dg-do run } */
-/* { dg-options "-O2 -fdump-tree-vrp1 -fdump-tree-optimized" } */
+/* { dg-options "-O2 -fdump-tree-vrp1 -fdump-tree-optimized -fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 __attribute__ ((noinline))
 int foo (int a, unsigned b)
index cf74e156109cf5cefd5939c08ab0840ae1bdaf3b..f9fc212f49e86cdaa6be8499d034640d9e5e570c 100644 (file)
@@ -124,7 +124,7 @@ enum STATES FMS( u8 **in , u32 *transitions) {
    to change decisions in switch expansion which in turn can expose new
    jump threading opportunities.  Skip the later tests on aarch64.  */
 /* { dg-final { scan-tree-dump "Jumps threaded: 1\[1-9\]" "thread1" } } */
-/* { dg-final { scan-tree-dump-times "Invalid sum" 3 "thread1" } } */
+/* { dg-final { scan-tree-dump-times "Invalid sum" 4 "thread1" } } */
 /* { dg-final { scan-tree-dump-not "optimizing for size" "thread1" } } */
 /* { dg-final { scan-tree-dump-not "optimizing for size" "thread2" } } */
 /* { dg-final { scan-tree-dump-not "optimizing for size" "thread3" { target { ! aarch64*-*-* } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-1.c
new file mode 100644 (file)
index 0000000..c3ccb5d
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-thread1-details --param logical-op-non-short-circuit=1" } */
+
+// Copied from ssa-dom-thread-11.c
+
+static int *bb_ticks;
+extern void frob (void);
+void
+mark_target_live_regs (int b, int block, int bb_tick)
+{
+  if (b == block && b != -1 && bb_tick == bb_ticks[b])
+      return;
+  if (b != -1)
+    frob ();
+}
+
+/* When the first two conditionals in the first IF are true, but
+   the third conditional is false, then there's a jump threading
+   opportunity to bypass the second IF statement.  */
+/* { dg-final { scan-tree-dump-times "Registering.*jump thread" 1 "thread1"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-2.c
new file mode 100644 (file)
index 0000000..d2689b6
--- /dev/null
@@ -0,0 +1,39 @@
+/* { dg-do compile } */ 
+/* { dg-options "-O2 -fdump-tree-thread2-details -w" } */
+
+// Copied from ssa-dom-thread-12.c.
+
+typedef long unsigned int size_t;
+union tree_node;
+typedef union tree_node *tree;
+typedef union gimple_statement_d *gimple;
+typedef const union gimple_statement_d *const_gimple;
+union gimple_statement_d
+{
+  unsigned num_ops;
+  tree exp;
+};
+
+unsigned int x;
+static inline tree
+gimple_op (const_gimple gs, unsigned i)
+{
+  if (!(i < gs->num_ops))
+    abort ();
+  return gs->exp;
+}
+
+unsigned char
+scan_function (gimple stmt)
+{
+  unsigned i;
+  for (i = 0; i < stmt->num_ops - 3 ; i++)
+    gimple_call_arg (stmt, i);
+  gimple_op (stmt, 1);
+}
+
+/* The test which bypasses the loop is simplified prior to DOM to check
+   that stmt->num_ops - 3 != 0.  When that test is false, we can derive
+   a value for stmt->num_ops.  That in turn allows us to thread the jump
+   for the conditional at the start of the call to gimple_op.  */
+/* { dg-final { scan-tree-dump-times "Registering.*jump thread" 1 "thread2"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-3.c b/gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-3.c
new file mode 100644 (file)
index 0000000..79ec067
--- /dev/null
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ethread-details -w --param logical-op-non-short-circuit=1" } */
+
+// Copied from ssa-dom-thread-14.c
+
+enum optab_methods
+{
+  OPTAB_DIRECT,
+  OPTAB_LIB,
+  OPTAB_WIDEN,
+  OPTAB_LIB_WIDEN,
+  OPTAB_MUST_WIDEN
+};
+struct optab_d { };
+typedef struct optab_d *optab;
+void
+expand_shift_1 (int code, int unsignedp, int rotate,
+               optab lshift_optab, optab rshift_arith_optab)
+{
+  int left = (code == 42 || code == 0xde);
+  int attempt;
+  enum optab_methods methods;
+  if (attempt == 0)
+    methods = OPTAB_DIRECT;
+  else if (attempt == 1)
+    methods = OPTAB_WIDEN;
+  if ((!unsignedp || (!left && methods == OPTAB_WIDEN)))
+    {
+      enum optab_methods methods1 = methods;
+      if (unsignedp)
+       methods1 = OPTAB_MUST_WIDEN;
+      expand_binop (left ? lshift_optab : rshift_arith_optab,
+                          unsignedp, methods1);
+    }
+}
+
+/* When UNSIGNEDP is true, LEFT is false and METHOD == OPTAB_WIDEN
+   we will enter the TRUE arm of the conditional and we can thread
+   the test to compute the first first argument of the expand_binop
+   call if we look backwards through the boolean logicals.  */
+/* { dg-final { scan-tree-dump-times "Registering.*jump thread" 1 "ethread"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-4.c b/gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-4.c
new file mode 100644 (file)
index 0000000..e8d1cfc
--- /dev/null
@@ -0,0 +1,83 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2 -fdump-tree-vrp-details -fdump-tree-thread1-details --param logical-op-non-short-circuit=1" }  */
+/* { dg-final { scan-tree-dump-times "Registering FSM jump" 8 "thread1" } }  */
+
+/* Copied from ssa-thread-14.  */
+
+void foo (void);
+void bar (void);
+void blah (void);
+
+/* One jump threaded here.  */
+
+void
+baz_1 (int a, int b, int c)
+{
+  if (a && b)
+    foo ();
+  if (!b && c)
+    bar ();
+}
+
+/* One jump threaded here.  */
+
+void
+baz_2 (int a, int b, int c)
+{
+  if (a && b)
+    foo ();
+  if (b || c)
+    bar ();
+}
+
+/* One jump threaded here.  */
+
+void
+baz_3 (int a, int b, int c)
+{
+  if (a && b > 10)
+    foo ();
+  if (b < 5 && c)
+    bar ();
+}
+
+/* Two jumps threaded here.  */
+
+void
+baz_4 (int a, int b, int c)
+{
+  if (a && b)
+    {
+      foo ();
+      if (c)
+        bar ();
+    }
+  if (b && c)
+    blah ();
+}
+
+/* Two jumps threaded here.  */
+
+void
+baz_5 (int a, int b, int c)
+{
+  if (a && b)
+    {
+      foo ();
+      if (c)
+        bar ();
+    }
+  if (!b || !c)
+    blah ();
+}
+
+/* One jump threaded here.  */
+
+void
+baz_6 (int a, int b, int c)
+{
+  if (a == 39 && b == 41)
+    foo ();
+  if (c == 12 || b == 41)
+    bar ();
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-5.c b/gcc/testsuite/gcc.dg/tree-ssa/ranger-threader-5.c
new file mode 100644 (file)
index 0000000..b7ca99a
--- /dev/null
@@ -0,0 +1,80 @@
+// { dg-do compile }
+// { dg-options "-fgimple -O2 -fdump-tree-thread1-details" }
+
+/* This tests that we can thread BB4->BB999 coming in through the
+   following path:
+
+      latch   many insns
+        |         |
+        V         V
+   6 -> 7 -> 3 -> 4 -> 999
+
+   The ranger based threader cannot thread this because BB4 has too
+   many instructions so it gives up looking back.  However, if we were
+   able to looking further, we would notice that a profitable path
+   passing through the loop latch (BB7) exists.
+
+   That is, 3->4->N in isolation is not profitable, but 6->7->3->4->N is.
+
+   It is not clear whether handling this case in the backwards
+   threader is profitable, as it would increase the search space
+   considerably.  The test is being added to note a regression from
+   the old backward threader code.
+
+   This test has been distilled from libphobos/src/std/net/isemail.d.
+
+   The ranger threader stops at the 3->4 subpath with: "did not thread
+   around loop and would copy too many statements".  */
+
+
+extern void bar();
+extern int random();
+
+int __GIMPLE (ssa,startwith("thread1"))
+foo (int key)
+{
+  int context;
+  int _1454;
+
+ __BB(2):
+  goto __BB3;
+
+  // Loop header.
+ __BB(3):
+  context_448 = __PHI (__BB2: 0, __BB7: context_450);
+  if (key_5(D) > 0)
+    goto __BB999;
+  else
+    goto __BB4;
+
+ __BB(4):
+  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();
+  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();
+  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();
+  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();
+  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();
+  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();  bar();
+  switch (context_448) {default: L5; case 0: L999; }
+
+ __BB(5):
+ L5:
+  goto __BB6;
+
+ __BB(6):
+  context_450 = __PHI (__BB5: 0);
+  _1454 = random ();
+  if (_1454 > 0)
+    goto __BB999;
+  else
+    goto __BB7;
+
+  // Loop latch.
+ __BB(7):
+  goto __BB3;
+
+ __BB(999):
+ L999:
+  return 5;
+}
+
+// { dg-final { scan-tree-dump-times "Registering.*jump thread.*incoming edge;  \\(6, 7\\)  \\(7, 3\\)  \\(3, 4\\)  \\(4, 999\\) nocopy" 1 "thread1" { xfail *-*-* } } }
index dac931c18d0009a142e5c8a10aecc3a8660afc60..8ef7646282ce548369204e198a6017c610b42153 100644 (file)
@@ -1,5 +1,7 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fsplit-paths -fdump-tree-split-paths-details -w" } */
+/* { dg-options "-O2 -fsplit-paths -fdump-tree-split-paths-details -w -fdisable-tree-thread1 -fdisable-tree-thread2" } */
+
+/* Note: Threader causes the infinite loop in val & 1 sooner.  */
 
 powi_cost (long n)
 {
index 5f90613263d3d013ff02097d1504ae3952a3907e..856ab389439b90cc7e0d8854a0d187a37542abe5 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-dom2-details --param logical-op-non-short-circuit=1" } */
+/* { dg-options "-O2 -fdump-tree-dom2-details --param logical-op-non-short-circuit=1 -fdisable-tree-thread1 -fdisable-tree-thread2" } */
 
 static int *bb_ticks;
 extern void frob (void);
index 63bd12a06a413cec1937f1011665d253cbefe640..bad5e0a782d31b14979e9ff1cced1714888a99e8 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */ 
-/* { dg-options "-O2 -fdump-tree-dom2-details -w" } */
+/* { dg-options "-O2 -fdump-tree-dom2-details -w -fdisable-tree-thread2" } */
 typedef long unsigned int size_t;
 union tree_node;
 typedef union tree_node *tree;
index 4e6a911506e17dfa78f318668f7490f38a875c8f..3bc4b3795cbee214c6acb0b3d2abd8eebd3c7d5f 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-tree-dom2-details -w --param logical-op-non-short-circuit=1" } */
+/* { dg-additional-options "-fdisable-tree-thread1 -fdisable-tree-ethread -fdisable-tree-thread2" } */
 
 enum optab_methods
 {
index d4759b8903b66669df9c4b58483dca68e4b2cfb1..03872e7a02fa71b70992c26760d14e609e93cfc8 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */ 
-/* { dg-options "-O2 -fdump-tree-vrp1-details -fdump-tree-dom2-details -std=gnu89 --param logical-op-non-short-circuit=0" } */
+/* { dg-options "-O2 -fdump-tree-vrp1-details -fdump-tree-thread1-details -std=gnu89 --param logical-op-non-short-circuit=0" } */
 
 #include "ssa-dom-thread-4.c"
 
@@ -21,4 +21,5 @@
         condition.
 
    All the cases are picked up by VRP1 as jump threads.  */
-/* { dg-final { scan-tree-dump-times "Threaded" 4 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Registering FSM jump" 6 "thread1" } } */
+/* { dg-final { scan-tree-dump-times "Threaded" 2 "vrp1" } } */
index 16a9ef4e28aa2f831c55fd0b4429853a2a9b2705..c7bf867b084408c2e0c6dec8003553624473b513 100644 (file)
@@ -34,8 +34,8 @@
      SWITCH_BB -> BBx -> BBy -> BBz -> PHI
 
    We now know the value of the switch index at PHI.  */
-/* { dg-final { scan-tree-dump-times "FSM" 6 "thread1" } } */
-/* { dg-final { scan-tree-dump-times "FSM" 1 "thread2" } } */
+/* { dg-final { scan-tree-dump-times "Registering FSM jump" 6 "thread1" } } */
+/* { dg-final { scan-tree-dump-times "Registering FSM jump" 1 "thread2" } } */
 
 int sum0, sum1, sum2, sum3;
 int foo (char *s, char **ret)
index bad5bc1d00379e35302b79928ed999af5e06157f..1c2d12aa9ea99226160364a0555ff0f6885af173 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-tree-thread1-stats -fdump-tree-thread2-stats -fdump-tree-dom2-stats -fdump-tree-thread3-stats -fdump-tree-dom3-stats -fdump-tree-vrp2-stats -fno-guess-branch-probability" } */
+/* { dg-additional-options "--param=threader-mode=legacy" } */
 
 /* Here we have the same issue as was commented in ssa-dom-thread-6.c.
    The PHI coming into the threader has a lot more constants, so the
index b3d610204daf5d63e0fc978747e7f0acd911c49e..5e74c78e7b03943a362913185c2d0e9fa98227b2 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-fre1-details" } */
+/* { dg-options "-O -fdump-tree-fre1-details -fdisable-tree-ethread" } */
 
 int foo (int i)
 {
index 67e1e89ecd3305c580cbac2a4f5cec347c9aca69..672a54e07dbfb263a145057402ecfb1409cf0d38 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-tree-vrp2-details --param logical-op-non-short-circuit=1" } */
+/* { dg-additional-options "-fdisable-tree-ethread -fdisable-tree-thread1 -fdisable-tree-thread2" } */
 /* { dg-final { scan-tree-dump-not "IRREDUCIBLE_LOOP" "vrp2" } } */
 
 void abort (void);
index fb9840e95d5861e0943c88cab59f7a0c3121a442..8f554641b284e97089031f9f6fcd53a2811c94f2 100644 (file)
@@ -2,7 +2,7 @@
 /* { dg-options "-O2 -fdump-tree-thread2-details -fdump-tree-thread3-details -fdump-tree-thread4-details -fno-finite-loops --param early-inlining-insns=14 -fno-inline-functions" } */
 /* { dg-final { scan-tree-dump "FSM" "thread2" } } */
 /* { dg-final { scan-tree-dump "FSM" "thread3" } } */
-/* { dg-final { scan-tree-dump "FSM" "thread4" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump "FSM" "thread4" } } */
 
 typedef struct bitmap_head_def *bitmap;
 typedef const struct bitmap_head_def *const_bitmap;
index 38661c888220568b4155708253e5509a93e6a123..f9152b9358f88b94f19e21560c96ed351ae817ea 100644 (file)
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-additional-options "-O2 -fdump-tree-vrp-details --param logical-op-non-short-circuit=1" }  */
+/* { dg-additional-options "-fdisable-tree-thread1" } */
 /* { dg-final { scan-tree-dump-times "Threaded jump" 8 "vrp1" } }  */
 
 void foo (void);
index 4be538f5944ee5834fe8c043d042a2f187e0f07b..2285c55c7d2573edcfe0008868ca6c08e4e7c6a8 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1 -fdelete-null-pointer-checks -fdisable-tree-evrp" } */
+/* { dg-options "-O2 -fdump-tree-vrp1 -fdelete-null-pointer-checks -fdisable-tree-evrp -fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 struct A
 {
index bafb65a53d63e5d1f2c94a5aca7f08de60e473c6..1d7ea4e8ffb251255e795e2f474e02e432c1a9ec 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 struct A
 {
index 8c611e91fcdc106774e69cd42c20565c3a9a18d3..c17cd1b5738de5b709a3f75e81992adb587ad4e1 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1 -fno-early-inlining" } */
+/* { dg-options "-O2 -fdump-tree-vrp1 -fno-early-inlining -fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 
 inline int ten()
index a872bc4373123a8d40878dc9afbf0df40e484f20..acb03c29aa42462d88012970d63298bde9c15812 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 int baz (void);
 
index 0f3f280e4e15c5ba82b8ee14e2d1bca7b9769090..31a541522f56dafa950c8fff0bff6ef82910b8ec 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1-details -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1-details -fdelete-null-pointer-checks -fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 int
 foo (int i, int *p)
index 56cc50c5f1d69e1b2397617bd3233d502cef7775..fad0051cb095579096bfeac56bd22e71066c1a3e 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1 -std=gnu89" } */
+/* { dg-options "-O2 -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1 -std=gnu89 -fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 foo (int *p)
 {
index 40373fde163bee41af7947d2d38663bfbd45200b..98a8da6d05e9f1ac4313f02b9286d4f500b17e53 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-fwrapv -O1 -ftree-vrp -fdisable-tree-evrp -fdump-tree-vrp1" } */
+/* { dg-options "-fwrapv -O1 -ftree-vrp -fdisable-tree-evrp -fdump-tree-vrp1 -fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 #include <limits.h>
 extern void abort ();
index 4a3b0d73648a775a0b807d5f41b07e6bfe848cad..f9df67ffb055004b2f64149cf6712f9050021979 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-fwrapv -O1 -fno-tree-fre -fdisable-tree-evrp -ftree-vrp -fdump-tree-vrp1" } */
+/* { dg-options "-fwrapv -O1 -fno-tree-fre -fdisable-tree-evrp -ftree-vrp -fdump-tree-vrp1 -fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 extern void abort ();
 extern void exit (int);
index f1d3863943e4e78dfa3e803ef8d3d21cd4b959de..88833eb701ea7cdcc3c38c1e5610af5800b14587 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1 -fno-tree-fre -fdisable-tree-evrp" } */
+/* { dg-options "-O2 -fdump-tree-vrp1 -fno-tree-fre -fdisable-tree-evrp -fdisable-tree-ethread -fdisable-tree-thread1" } */
 
 /* This is from PR14052.  */
 
index 1dbf756f01da92762cf87f663117c042a006f73e..d8f9c80291a9642d3c6f471ac3df0ea032455b7f 100644 (file)
@@ -29,7 +29,7 @@ void foo_c5_1_1 (int x, int y, int z, int a)
     w = __LINE__;
 
   if (x || y || a)
-    p = w;          // { dg-bogus "-Wmaybe-uninitialized" "pr61112" { xfail *-*-* } }
+    p = w;
 }
 
 void foo_c5_1_2 (int x, int y, int z, int a)
@@ -43,7 +43,7 @@ void foo_c5_1_2 (int x, int y, int z, int a)
     w = __LINE__;
 
   if (x || a || y)
-    p = w;          // { dg-bogus "-Wmaybe-uninitialized" "pr61112" { xfail *-*-* } }
+    p = w;
 }
 
 void foo_c5_1_3 (int x, int y, int z, int a)
@@ -57,7 +57,7 @@ void foo_c5_1_3 (int x, int y, int z, int a)
     w = __LINE__;
 
   if (a || x || y)
-    p = w;          // { dg-bogus "-Wmaybe-uninitialized" "pr61112" { xfail *-*-* } }
+    p = w;
 }
 
 void foo_c5_2 (int x, int y, int z, int a)
index d9ae75e0765757f615632e6b9fcea1505107534f..d46d6659a616de618352e31874c0e998f05c95f9 100644 (file)
@@ -1,6 +1,7 @@
 
 /* { dg-do compile } */
 /* { dg-options "-Wuninitialized -O2" } */
+/* { dg-xfail-if "threading shuffles things around" { ppc64*-*-* } } */
 
 int g;
 void bar();
index e68a9b6253534be8b35ee0e8961dd66dff68c63c..664e93e9b606fefa9b646106a42bce972607c854 100644 (file)
@@ -1,5 +1,8 @@
 /* { dg-require-effective-target vect_int } */
 
+/* See note below as to why we disable threading.  */
+/* { dg-additional-options "-fdisable-tree-thread1" } */
+
 #include <stdarg.h>
 #include "tree-vect.h"
 
@@ -27,6 +30,10 @@ main1 (int dummy)
       *pout++ = *pin++ + a;
       *pout++ = *pin++ + a;
       *pout++ = *pin++ + a;
+      /* In some architectures like ppc64, jump threading may thread
+        the iteration where i==0 such that we no longer optimize the
+        BB.  Another alternative to disable jump threading would be
+        to wrap the read from `i' into a function returning i.  */
       if (arr[i] = i)
         a = i;
       else
index 1ea111795a48f1cf69884f041023f45777cf1941..5719279185729b645db592a52825796896b2f050 100644 (file)
@@ -1,6 +1,6 @@
 /* { dg-do run } */
 /* { dg-require-effective-target avx2 } */
-/* { dg-options "-mavx2 -O3 -fopenmp-simd -fdump-tree-vect-details" } */
+/* { dg-options "-mavx2 -O3 -fopenmp-simd -fdump-tree-vect-details -fdisable-tree-thread1" } */
 
 #include "avx2-check.h"
 #define N 64
index 7dd8594e3d424fab65e8a5618c4faf078f52f3cb..2c0e9751101ca745dcbc6dd70710c3fdbfa57dba 100644 (file)
@@ -36,6 +36,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-phinodes.h"
 #include "tree-inline.h"
 #include "tree-vectorizer.h"
+#include "value-range.h"
+#include "gimple-range.h"
+#include "tree-ssa-threadedge.h"
+#include "gimple-range-path.h"
+#include "ssa.h"
+#include "tree-cfgcleanup.h"
 
 // Path registry for the backwards threader.  After all paths have been
 // registered with register_path(), thread_through_all_blocks() is called
@@ -71,13 +77,415 @@ private:
   const bool m_speed_p;
 };
 
+// Ranger based backwards threader.
+
+class back_threader
+{
+  // Temporary until we remove old code.
+  friend bool path_is_unreachable_p (const vec<jump_thread_edge *> &);
+
+public:
+  back_threader (back_threader_profitability &, back_threader_registry &);
+  ~back_threader ();
+  void find_paths (basic_block bb, tree name);
+
+private:
+  void maybe_register_path (edge taken_edge);
+  bool find_paths_to_names (basic_block bb, bitmap imports);
+  bool resolve_def (tree name, bitmap interesting, vec<tree> worklist);
+  bool resolve_phi (gphi *phi, bitmap imports);
+  edge find_taken_edge (const vec<basic_block> &path);
+  edge find_taken_edge_cond (const vec<basic_block> &path, gcond *);
+  edge find_taken_edge_switch (const vec<basic_block> &path, gswitch *);
+
+  back_threader_registry &m_registry;
+  back_threader_profitability &m_profit;
+  gimple_ranger m_ranger;
+  path_range_query m_solver;
+
+  // Current path being analyzed.
+  auto_vec<basic_block> m_path;
+  // Hash to mark visited BBs while analyzing a path.
+  hash_set<basic_block> m_visited_bbs;
+  // The set of SSA names, any of which could potentially change the
+  // value of the final conditional in a path.
+  bitmap m_imports;
+  // The last statement in the path.
+  gimple *m_last_stmt;
+  // This is a bit of a wart.  It's used to pass the LHS SSA name to
+  // the profitability engine.
+  tree m_name;
+  // Marker to differentiate unreachable edges.
+  static const edge UNREACHABLE_EDGE;
+};
+
+// Used to differentiate unreachable edges, so we may stop the search
+// in a the given direction.
+const edge back_threader::UNREACHABLE_EDGE = (edge) -1;
+
+back_threader::back_threader (back_threader_profitability &profit,
+                             back_threader_registry &registry)
+  : m_registry (registry),
+    m_profit (profit),
+    m_solver (m_ranger)
+{
+  m_last_stmt = NULL;
+  m_imports = BITMAP_ALLOC (NULL);
+}
+
+back_threader::~back_threader ()
+{
+  m_path.release ();
+  BITMAP_FREE (m_imports);
+}
+
+// Register the current path for jump threading if it's profitable to
+// do so.  TAKEN_EDGE is the known edge out of the path.
+
+void
+back_threader::maybe_register_path (edge taken_edge)
+{
+  bool irreducible = false;
+  bool profitable
+    = m_profit.profitable_path_p (m_path, m_name, taken_edge, &irreducible);
+
+  if (profitable)
+    {
+      m_registry.register_path (m_path, taken_edge);
+
+      if (irreducible)
+       vect_free_loop_info_assumptions (m_path[0]->loop_father);
+    }
+}
+
+// Return the known taken edge out of a path.  If the path can be
+// determined to be unreachable, return UNREACHABLE_EDGE.  If no
+// outgoing edge can be calculated, return NULL.
+
+edge
+back_threader::find_taken_edge (const vec<basic_block> &path)
+{
+  gcc_checking_assert (path.length () > 1);
+  switch (gimple_code (m_last_stmt))
+    {
+    case GIMPLE_COND:
+      return find_taken_edge_cond (path, as_a<gcond *> (m_last_stmt));
+
+    case GIMPLE_SWITCH:
+      return find_taken_edge_switch (path, as_a<gswitch *> (m_last_stmt));
+
+    default:
+      return NULL;
+    }
+}
+
+// Same as find_taken_edge, but for paths ending in a switch.
+
+edge
+back_threader::find_taken_edge_switch (const vec<basic_block> &path,
+                                      gswitch *sw)
+{
+  tree name = gimple_switch_index (sw);
+  int_range_max r;
+
+  m_solver.precompute_ranges (path, m_imports);
+  m_solver.range_of_expr (r, name, sw);
+
+  if (r.undefined_p ())
+    return UNREACHABLE_EDGE;
+
+  if (r.varying_p ())
+    return NULL;
+
+  tree val;
+  if (r.singleton_p (&val))
+    return ::find_taken_edge (gimple_bb (sw), val);
+
+  return NULL;
+}
+
+// Same as find_taken_edge, but for paths ending in a GIMPLE_COND.
+
+edge
+back_threader::find_taken_edge_cond (const vec<basic_block> &path,
+                                    gcond *cond)
+{
+  m_solver.precompute_ranges (path, m_imports);
+
+  // Check if either operand is unreachable since this knowledge could
+  // help the caller cut down the search space.
+  int_range_max r;
+  m_solver.range_of_expr (r, gimple_cond_lhs (cond));
+  if (r.undefined_p ())
+    return UNREACHABLE_EDGE;
+  m_solver.range_of_expr (r, gimple_cond_rhs (cond));
+  if (r.undefined_p ())
+    return UNREACHABLE_EDGE;
+
+  m_solver.range_of_stmt (r, cond);
+
+  int_range<2> true_range (boolean_true_node, boolean_true_node);
+  int_range<2> false_range (boolean_false_node, boolean_false_node);
+
+  if (r == true_range || r == false_range)
+    {
+      edge e_true, e_false;
+      basic_block bb = gimple_bb (cond);
+      extract_true_false_edges_from_block (bb, &e_true, &e_false);
+      return r == true_range ? e_true : e_false;
+    }
+  return NULL;
+}
+
+// Populate a vector of trees from a bitmap.
+
+static inline void
+populate_worklist (vec<tree> worklist, bitmap bits)
+{
+  bitmap_iterator bi;
+  unsigned i;
+
+  EXECUTE_IF_SET_IN_BITMAP (bits, 0, i, bi)
+    {
+      tree name = ssa_name (i);
+      worklist.quick_push (name);
+    }
+}
+
+// If taking any of the incoming edges to a PHI causes the final
+// conditional of the current path to be constant, register the
+// path(s), and return TRUE.
+
+bool
+back_threader::resolve_phi (gphi *phi, bitmap interesting)
+{
+  if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (phi)))
+    return true;
+
+  bool done = false;
+  for (size_t i = 0; i < gimple_phi_num_args (phi); ++i)
+    {
+      edge e = gimple_phi_arg_edge (phi, i);
+
+      // This is like path_crosses_loops in profitable_path_p but more
+      // restrictive, since profitable_path_p allows threading the
+      // first block because it would be redirected anyhow.
+      //
+      // If we loosened the restriction and used profitable_path_p()
+      // here instead, we would peel off the first iterations of loops
+      // in places like tree-ssa/pr14341.c.
+      bool profitable_p = m_path[0]->loop_father == e->src->loop_father;
+      if (!profitable_p)
+       {
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           fprintf (dump_file,
+                    "  FAIL: path through PHI in bb%d (incoming bb:%d) crosses loop\n",
+                    e->dest->index, e->src->index);
+         continue;
+       }
+
+      tree arg = gimple_phi_arg_def (phi, i);
+      if (TREE_CODE (arg) == SSA_NAME)
+       {
+         unsigned v = SSA_NAME_VERSION (arg);
+
+         // Avoid loops as in: x_5 = PHI <x_5(2), ...>.
+         if (bitmap_bit_p (interesting, v))
+           continue;
+
+         bitmap_set_bit (interesting, v);
+         bitmap_set_bit (m_imports, v);
+         done |= find_paths_to_names (e->src, interesting);
+         bitmap_clear_bit (interesting, v);
+       }
+      else if (TREE_CODE (arg) == INTEGER_CST)
+       {
+         m_path.safe_push (e->src);
+         edge taken_edge = find_taken_edge (m_path);
+         if (taken_edge && taken_edge != UNREACHABLE_EDGE)
+           {
+             maybe_register_path (taken_edge);
+             done = true;
+           }
+         m_path.pop ();
+       }
+    }
+  return done;
+}
+
+// If the definition of NAME causes the final conditional of the
+// current path to be constant, register the path, and return TRUE.
+
+bool
+back_threader::resolve_def (tree name, bitmap interesting, vec<tree> worklist)
+{
+  gimple *def_stmt = SSA_NAME_DEF_STMT (name);
+
+  // Handle PHIs.
+  if (is_a<gphi *> (def_stmt)
+      && resolve_phi (as_a<gphi *> (def_stmt), interesting))
+    return true;
+
+  // Defer copies of SSAs by adding the source to the worklist.
+  if (gimple_assign_single_p (def_stmt)
+      && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME)
+    {
+      tree rhs = gimple_assign_rhs1 (def_stmt);
+      bitmap_set_bit (m_imports, SSA_NAME_VERSION (rhs));
+      bitmap_set_bit (interesting, SSA_NAME_VERSION (rhs));
+      worklist.safe_push (rhs);
+    }
+  return false;
+}
+
+// Find jump threading paths to any of the SSA names in the
+// INTERESTING bitmap, and register any such paths.
+//
+// Return TRUE if no further processing past this block is necessary.
+// This is because we've either registered a path, or because there is
+// nothing of interesting beyond this block.
+//
+// BB is the current path being processed.
+
+bool
+back_threader::find_paths_to_names (basic_block bb, bitmap interesting)
+{
+  if (m_visited_bbs.add (bb))
+    return true;
+
+  m_path.safe_push (bb);
+
+  if (m_path.length () > 1
+      && !m_profit.profitable_path_p (m_path, m_name, NULL))
+    {
+      m_path.pop ();
+      m_visited_bbs.remove (bb);
+      return false;
+    }
+
+  auto_bitmap processed;
+  unsigned i;
+  bool done = false;
+
+  // We use a worklist instead of iterating through the bitmap,
+  // because we may add new items in-flight.
+  auto_vec<tree> worklist (bitmap_count_bits (interesting));
+  populate_worklist (worklist, interesting);
+  while (!worklist.is_empty ())
+    {
+      tree name = worklist.pop ();
+      unsigned i = SSA_NAME_VERSION (name);
+      basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (name));
+
+      // Process any names defined in this block.
+      if (def_bb == bb)
+       {
+         bitmap_set_bit (processed, i);
+
+         if (resolve_def (name, interesting, worklist))
+           {
+             done = true;
+             goto leave_bb;
+           }
+       }
+      // Examine blocks that define or export an interesting SSA,
+      // since they may compute a range which resolve this path.
+      if ((def_bb == bb
+          || bitmap_bit_p (m_ranger.gori ().exports (bb), i))
+         && m_path.length () > 1)
+       {
+         edge taken_edge = find_taken_edge (m_path);
+         if (taken_edge)
+           {
+             if (taken_edge != UNREACHABLE_EDGE)
+               maybe_register_path (taken_edge);
+
+             done = true;
+             goto leave_bb;
+           }
+       }
+    }
+
+  // If there are interesting names not yet processed, keep looking.
+  bitmap_and_compl_into (interesting, processed);
+  if (!bitmap_empty_p (interesting))
+    {
+      edge_iterator iter;
+      edge e;
+      FOR_EACH_EDGE (e, iter, bb->preds)
+       if ((e->flags & EDGE_ABNORMAL) == 0)
+         done |= find_paths_to_names (e->src, interesting);
+    }
+
+ leave_bb:
+  bitmap_iterator bi;
+  EXECUTE_IF_SET_IN_BITMAP (processed, 0, i, bi)
+    bitmap_set_bit (interesting, i);
+
+  m_path.pop ();
+  m_visited_bbs.remove (bb);
+  return done;
+}
+
+// Search backwards from BB looking for paths where the final
+// conditional out of BB can be determined.  NAME is the LHS of the
+// final conditional.  Register such paths for jump threading.
+
+void
+back_threader::find_paths (basic_block bb, tree name)
+{
+  gimple *stmt = last_stmt (bb);
+  if (!stmt
+      || (gimple_code (stmt) != GIMPLE_COND
+         && gimple_code (stmt) != GIMPLE_SWITCH))
+    return;
+
+  if (EDGE_COUNT (bb->succs) > 1
+      || single_succ_to_potentially_threadable_block (bb))
+    {
+      m_last_stmt = stmt;
+      m_visited_bbs.empty ();
+      m_path.truncate (0);
+      m_name = name;
+      bitmap_clear (m_imports);
+
+      auto_bitmap interesting;
+      bitmap_copy (m_imports, m_ranger.gori ().imports (bb));
+      bitmap_copy (interesting, m_imports);
+      find_paths_to_names (bb, interesting);
+    }
+}
+
+// Dump a sequence of BBs through the CFG.
+
+DEBUG_FUNCTION void
+dump_path (FILE *dump_file, const vec<basic_block> &path)
+{
+  for (size_t i = 0; i < path.length (); ++i)
+    {
+      fprintf (dump_file, "BB%d", path[i]->index);
+      if (i + 1 < path.length ())
+       fprintf (dump_file, " <- ");
+    }
+  fprintf (dump_file, "\n");
+}
+
+DEBUG_FUNCTION void
+debug (const vec <basic_block> &path)
+{
+  dump_path (stderr, path);
+}
+
 class thread_jumps
 {
 public:
   thread_jumps (bool speed_p = true)
-    : m_profit (speed_p), m_registry (param_max_fsm_thread_paths)
+    : m_profit (speed_p),
+      m_registry (param_max_fsm_thread_paths),
+      m_back_threader (m_profit, m_registry)
   { }
   void find_jump_threads_backwards (basic_block bb);
+  void find_jump_threads_backwards_with_ranger (basic_block bb);
   bool thread_through_all_blocks ();
 
 private:
@@ -102,6 +510,7 @@ private:
   tree m_name;
   back_threader_profitability m_profit;
   back_threader_registry m_registry;
+  back_threader m_back_threader;
 };
 
 // Perform the actual jump threading for the all queued paths.
@@ -548,8 +957,8 @@ back_threader_registry::register_path (const vec<basic_block> &m_path,
                                                EDGE_NO_COPY_SRC_BLOCK);
   jump_thread_path->safe_push (x);
 
-  m_lowlevel_registry.register_jump_thread (jump_thread_path);
-  ++m_threaded_paths;
+  if (m_lowlevel_registry.register_jump_thread (jump_thread_path))
+    ++m_threaded_paths;
   return true;
 }
 
@@ -818,6 +1227,12 @@ thread_jumps::fsm_find_control_statement_thread_paths (tree name)
 void
 thread_jumps::find_jump_threads_backwards (basic_block bb)
 {
+  if (param_threader_mode & THREADER_MODE_RANGER)
+    {
+      find_jump_threads_backwards_with_ranger (bb);
+      return;
+    }
+
   gimple *stmt = get_gimple_control_stmt (bb);
   if (!stmt)
     return;
@@ -850,6 +1265,28 @@ thread_jumps::find_jump_threads_backwards (basic_block bb)
   fsm_find_control_statement_thread_paths (name);
 }
 
+// Like find_jump_threads_backwards(), but using ranger.
+
+void
+thread_jumps::find_jump_threads_backwards_with_ranger (basic_block bb)
+{
+  gimple *stmt = get_gimple_control_stmt (bb);
+  if (!stmt)
+    return;
+
+  enum gimple_code code = gimple_code (stmt);
+  tree name = NULL;
+  if (code == GIMPLE_SWITCH)
+    name = gimple_switch_index (as_a <gswitch *> (stmt));
+  else if (code == GIMPLE_GOTO)
+    name = gimple_goto_dest (stmt);
+  else if (code == GIMPLE_COND)
+    name = gimple_cond_lhs (stmt);
+
+  m_name = name;
+  m_back_threader.find_paths (bb, name);
+}
+
 namespace {
 
 const pass_data pass_data_thread_jumps =
@@ -883,12 +1320,12 @@ pass_thread_jumps::gate (function *fun ATTRIBUTE_UNUSED)
   return flag_expensive_optimizations;
 }
 
+// Try to thread blocks in FUN.  Return TRUE if any jump thread paths were
+// registered.
 
-unsigned int
-pass_thread_jumps::execute (function *fun)
+static bool
+try_thread_blocks (function *fun)
 {
-  loop_optimizer_init (LOOPS_HAVE_PREHEADERS | LOOPS_HAVE_SIMPLE_LATCHES);
-
   /* Try to thread each block with more than one successor.  */
   thread_jumps threader;
   basic_block bb;
@@ -897,7 +1334,30 @@ pass_thread_jumps::execute (function *fun)
       if (EDGE_COUNT (bb->succs) > 1)
        threader.find_jump_threads_backwards (bb);
     }
-  bool changed = threader.thread_through_all_blocks ();
+  return threader.thread_through_all_blocks ();
+}
+
+unsigned int
+pass_thread_jumps::execute (function *fun)
+{
+  loop_optimizer_init (LOOPS_HAVE_PREHEADERS | LOOPS_HAVE_SIMPLE_LATCHES);
+
+  // Iterative mode is a testing construct and is not meant for public
+  // consumption.  It is OFF by default.
+  bool iterative = param_threader_iterative;
+
+  bool changed = false;
+  while (try_thread_blocks (fun))
+    {
+      changed = true;
+
+      if (!iterative)
+       break;
+
+      if ((param_threader_mode & THREADER_MODE_RANGER) == 0)
+       break;
+      cleanup_tree_cfg (TODO_update_ssa);
+    }
 
   loop_optimizer_finalize ();
   return changed ? TODO_cleanup_cfg : 0;
index 24ccf014416ae789576ce941729d5c0726b49aaf..37ee5c11be373d7affe5a7e0a3f0fdbd3968a2bc 100644 (file)
@@ -1261,6 +1261,18 @@ jump_threader::thread_across_edge (edge e)
   m_state->pop ();
 }
 
+/* Return TRUE if BB has a single successor to a block with multiple
+   incoming and outgoing edges.  */
+
+bool
+single_succ_to_potentially_threadable_block (basic_block bb)
+{
+  int flags = (EDGE_IGNORE | EDGE_COMPLEX | EDGE_ABNORMAL);
+  return (single_succ_p (bb)
+         && (single_succ_edge (bb)->flags & flags) == 0
+         && potentially_threadable_block (single_succ (bb)));
+}
+
 /* Examine the outgoing edges from BB and conditionally
    try to thread them.  */
 
@@ -1274,12 +1286,8 @@ jump_threader::thread_outgoing_edges (basic_block bb)
      outgoing edges, then we may be able to thread the edge, i.e., we
      may be able to statically determine which of the outgoing edges
      will be traversed when the incoming edge from BB is traversed.  */
-  if (single_succ_p (bb)
-      && (single_succ_edge (bb)->flags & flags) == 0
-      && potentially_threadable_block (single_succ (bb)))
-    {
-      thread_across_edge (single_succ_edge (bb));
-    }
+  if (single_succ_to_potentially_threadable_block (bb))
+    thread_across_edge (single_succ_edge (bb));
   else if ((last = last_stmt (bb))
           && gimple_code (last) == GIMPLE_COND
           && EDGE_COUNT (bb->succs) == 2
index c0d3c921e0f9ee6bb1860fd1a8e29c3785001230..0002b200d8b6d61a022233f3142a11a5a35ac05e 100644 (file)
@@ -94,6 +94,7 @@ protected:
 };
 
 extern void propagate_threaded_block_debug_into (basic_block, basic_block);
+extern bool single_succ_to_potentially_threadable_block (basic_block);
 
 // ?? All this ssa_name_values stuff is the store of values for
 // avail_exprs_stack and const_and_copies, so it really belongs in the
index f496dd3eb8c6f9ae78fd7bf70de95af3ac0e118a..29cf010e9ca72d9bf858cf4a7f1989a41cec981d 100644 (file)
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "tree-cfg.h"
 #include "tree-vectorizer.h"
+#include "tree-pass.h"
 
 /* Given a block B, update the CFG and SSA graph to reflect redirecting
    one or more in-edges to B to instead reach the destination of an
@@ -2741,15 +2742,17 @@ jump_thread_path_registry::thread_through_all_blocks
 
    E is the edge we can thread, E2 is the new target edge, i.e., we
    are effectively recording that E->dest can be changed to E2->dest
-   after fixing the SSA graph.  */
+   after fixing the SSA graph.
 
-void
+   Return TRUE if PATH was successfully threaded.  */
+
+bool
 jump_thread_path_registry::register_jump_thread (vec<jump_thread_edge *> *path)
 {
   if (!dbg_cnt (registered_jump_thread))
     {
       path->release ();
-      return;
+      return false;
     }
 
   /* First make sure there are no NULL outgoing edges on the jump threading
@@ -2766,7 +2769,7 @@ jump_thread_path_registry::register_jump_thread (vec<jump_thread_edge *> *path)
            }
 
          path->release ();
-         return;
+         return false;
        }
 
       /* Only the FSM threader is allowed to thread across
@@ -2780,6 +2783,7 @@ jump_thread_path_registry::register_jump_thread (vec<jump_thread_edge *> *path)
     dump_jump_thread_path (dump_file, *path, true);
 
   m_paths.safe_push (path);
+  return true;
 }
 
 /* Return how many uses of T there are within BB, as long as there
index b806caee5817fd66a35400bae2c44df472315bb8..2030bda15af411f9bd7ac77c0d9c7d2aef41a613 100644 (file)
@@ -63,7 +63,7 @@ class jump_thread_path_registry
 public:
   jump_thread_path_registry ();
   ~jump_thread_path_registry ();
-  void register_jump_thread (vec<jump_thread_edge *> *);
+  bool register_jump_thread (vec<jump_thread_edge *> *);
   void remove_jump_threads_including (edge);
   bool thread_through_all_blocks (bool);
   jump_thread_edge *allocate_thread_edge (edge e, jump_thread_edge_type t);
index d2af142e8fe641d44add31e71bf55ce3045efdb3..ef6f64d229be1b51c454aa85cb33c8bcb406daa8 100644 (file)
@@ -1,4 +1,5 @@
 /* Autopar with IF conditions.  */
+/* { dg-additional-options "-fdisable-tree-thread1" } */
 
 void abort();
 
index 32ba5ab84efe4691c66f8bfe251efec561f1c023..a97eb97acf6d7a4c9851c1d8351279af9e9d7b83 100644 (file)
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fdisable-tree-thread1" } */
+
 #define N 1500
 
 int x[N][N], y[N];