Teach VRP to register assertions along default switch labels (PR18046)
authorPatrick Palka <ppalka@gcc.gnu.org>
Tue, 26 Jul 2016 15:19:58 +0000 (15:19 +0000)
committerPatrick Palka <ppalka@gcc.gnu.org>
Tue, 26 Jul 2016 15:19:58 +0000 (15:19 +0000)
gcc/ChangeLog:

PR tree-optimization/18046
* genmodes.c (emit_mode_size_inline): Emit an assert that
verifies that mode is a valid array index.
(emit_mode_nuinits_inline): Likewise.
(emit_mode_inner_inline): Likewise.
(emit_mode_unit_size_inline): Likewise.
(emit_mode_unit_precision_inline): Likewise.
* tree-vrp.c: Include params.h.
(find_switch_asserts): Register edge assertions for the default
label which correspond to the anti-ranges of each case label.
* params.def (PARAM_MAX_VRP_SWITCH_ASSERTIONS): New.
* doc/invoke.texi: Document it.

gcc/testsuite/ChangeLog:

PR tree-optimization/18046
* gcc.dg/tree-ssa/ssa-dom-thread-6.c: Bump FSM count to 5.
* gcc.dg/tree-ssa/vrp103.c: New test.
* gcc.dg/tree-ssa/vrp104.c: New test.

From-SVN: r238761

gcc/ChangeLog
gcc/doc/invoke.texi
gcc/genmodes.c
gcc/params.def
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-6.c
gcc/testsuite/gcc.dg/tree-ssa/vrp103.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/vrp104.c [new file with mode: 0644]
gcc/tree-vrp.c

index ecb16027cf756b355566e4f91920e863d784fdde..d853f3becc16c21f7b77288be7cb8c7fe33e5d48 100644 (file)
@@ -1,3 +1,18 @@
+2016-07-26  Patrick Palka  <ppalka@gcc.gnu.org>
+
+       PR tree-optimization/18046
+       * genmodes.c (emit_mode_size_inline): Emit an assert that
+       verifies that mode is a valid array index.
+       (emit_mode_nuinits_inline): Likewise.
+       (emit_mode_inner_inline): Likewise.
+       (emit_mode_unit_size_inline): Likewise.
+       (emit_mode_unit_precision_inline): Likewise.
+       * tree-vrp.c: Include params.h.
+       (find_switch_asserts): Register edge assertions for the default
+       label which correspond to the anti-ranges of each case label.
+       * params.def (PARAM_MAX_VRP_SWITCH_ASSERTIONS): New.
+       * doc/invoke.texi: Document it.
+
 2016-07-26  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
 
        * gimple-ssa-strength-reduction.c (slsr_process_phi): Remove dead
index 79c842df6b327632f704614216e878becea2eb4f..22001f9a6a5ceb93c24df19380f435de99c8a057 100644 (file)
@@ -9781,6 +9781,10 @@ enable it.
 The maximum number of may-defs we analyze when looking for a must-def
 specifying the dynamic type of an object that invokes a virtual call
 we may be able to devirtualize speculatively.
+
+@item max-vrp-switch-assertions
+The maximum number of assertions to add along the default edge of a switch
+statement during VRP.  The default is 10.
 @end table
 @end table
 
index 097cc80f33e132d15e890caf104917d690454451..1170d4f5b0cd84c8b36aaa5a1e2c50bd229113b9 100644 (file)
@@ -976,6 +976,7 @@ unsigned char\n\
 mode_size_inline (machine_mode mode)\n\
 {\n\
   extern %sunsigned char mode_size[NUM_MACHINE_MODES];\n\
+  gcc_assert (mode >= 0 && mode < NUM_MACHINE_MODES);\n\
   switch (mode)\n\
     {\n", adj_bytesize ? "" : "const ");
 
@@ -1006,6 +1007,7 @@ unsigned char\n\
 mode_nunits_inline (machine_mode mode)\n\
 {\n\
   extern const unsigned char mode_nunits[NUM_MACHINE_MODES];\n\
+  gcc_assert (mode >= 0 && mode < NUM_MACHINE_MODES);\n\
   switch (mode)\n\
     {");
 
@@ -1035,6 +1037,7 @@ unsigned char\n\
 mode_inner_inline (machine_mode mode)\n\
 {\n\
   extern const unsigned char mode_inner[NUM_MACHINE_MODES];\n\
+  gcc_assert (mode >= 0 && mode < NUM_MACHINE_MODES);\n\
   switch (mode)\n\
     {");
 
@@ -1067,6 +1070,7 @@ mode_unit_size_inline (machine_mode mode)\n\
 {\n\
   extern CONST_MODE_UNIT_SIZE unsigned char mode_unit_size[NUM_MACHINE_MODES];\
 \n\
+  gcc_assert (mode >= 0 && mode < NUM_MACHINE_MODES);\n\
   switch (mode)\n\
     {");
 
@@ -1103,6 +1107,7 @@ unsigned short\n\
 mode_unit_precision_inline (machine_mode mode)\n\
 {\n\
   extern const unsigned short mode_unit_precision[NUM_MACHINE_MODES];\n\
+  gcc_assert (mode >= 0 && mode < NUM_MACHINE_MODES);\n\
   switch (mode)\n\
     {");
 
index 166032e7fb01726469f87bcf7a08aabbe2b6ffda..79b7dd4cca9ec1bb67a64725fb1a596b6e937419 100644 (file)
@@ -1246,6 +1246,12 @@ DEFPARAM (PARAM_MAX_SPECULATIVE_DEVIRT_MAYDEFS,
          "Maximum number of may-defs visited when devirtualizing "
          "speculatively", 50, 0, 0)
 
+DEFPARAM (PARAM_MAX_VRP_SWITCH_ASSERTIONS,
+         "max-vrp-switch-assertions",
+         "Maximum number of assertions to add along the default "
+         "edge of a switch statement during VRP",
+         10, 0, 0)
+
 /*
 
 Local variables:
index 45ea6a0f71e72ca70324608b553674ef73f0f036..5130a82bd58889bea187e1ebc3a6362b3d797b71 100644 (file)
@@ -1,3 +1,10 @@
+2016-07-26  Patrick Palka  <ppalka@gcc.gnu.org>
+
+       PR tree-optimization/18046
+       * gcc.dg/tree-ssa/ssa-dom-thread-6.c: Bump FSM count to 5.
+       * gcc.dg/tree-ssa/vrp103.c: New test.
+       * gcc.dg/tree-ssa/vrp104.c: New test.
+
 2016-07-26  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
 
        * gcc.target/powerpc/pr63354.c: Require lp64 since
index 5ec4687d1270b10cda873965e05413f6f5099891..551fbac3dad581d2532313f75c75624f23b10e35 100644 (file)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-tree-thread1-details -fdump-tree-thread2-details" } */
 /* { dg-final { scan-tree-dump-times "FSM" 3 "thread1" } } */
-/* { dg-final { scan-tree-dump-times "FSM" 4 "thread2" } } */
+/* { dg-final { scan-tree-dump-times "FSM" 5 "thread2" } } */
 
 int sum0, sum1, sum2, sum3;
 int foo (char *s, char **ret)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp103.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp103.c
new file mode 100644 (file)
index 0000000..2d63fc8
--- /dev/null
@@ -0,0 +1,30 @@
+/* PR tree-optimization/18046  */
+/* { dg-options "-O2 -fdump-tree-vrp" }  */
+/* { dg-final { scan-tree-dump-times "baz \\(0\\);" 4 "vrp1" } }  */
+
+void foo (void);
+void bar (void);
+void baz (int);
+
+void
+test (int i)
+{
+  switch (i)
+    {
+    case 1:
+    case 2:
+    case 3:
+      foo ();
+      break;
+    case 5:
+      bar ();
+      break;
+    default:
+      /* These tests should be folded to 0, resulting in 4 calls of baz(0).  */
+      baz (i == 1);
+      baz (i == 2);
+      baz (i == 3);
+      baz (i == 5);
+      break;
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp104.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp104.c
new file mode 100644 (file)
index 0000000..2c3db2e
--- /dev/null
@@ -0,0 +1,36 @@
+/* PR tree-optimization/18046  */
+/* { dg-options "-O2 -fdump-tree-optimized" }  */
+/* { dg-final { scan-tree-dump-times "switch" 1 "optimized" } }  */
+
+void foo (void);
+void bar (void);
+void baz (void);
+
+void
+test (int i)
+{
+  switch (i)
+    {
+    case 1:
+      foo ();
+      break;
+    case 2:
+      bar ();
+      break;
+    default:
+      break;
+    }
+
+  /* This switch should be gone after threading/VRP.  */
+  switch (i)
+    {
+    case 1:
+      foo ();
+      break;
+    case 2:
+      baz ();
+      break;
+    default:
+      break;
+    }
+}
index 06364b70f3317acc4cc9c0510b003ea36ba4946c..69868272896a65a0d11535106463da3f5a245ddb 100644 (file)
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "omp-low.h"
 #include "target.h"
 #include "case-cfn-macros.h"
+#include "params.h"
 
 /* Range of values that can be associated with an SSA_NAME after VRP
    has executed.  */
@@ -5917,6 +5918,7 @@ find_switch_asserts (basic_block bb, gswitch *last)
       ci[idx].expr = gimple_switch_label (last, idx);
       ci[idx].bb = label_to_block (CASE_LABEL (ci[idx].expr));
     }
+  edge default_edge = find_edge (bb, ci[0].bb);
   qsort (ci, n, sizeof (struct case_info), compare_case_labels);
 
   for (idx = 0; idx < n; ++idx)
@@ -5945,8 +5947,8 @@ find_switch_asserts (basic_block bb, gswitch *last)
            max = CASE_LOW (ci[idx].expr);
        }
 
-      /* Nothing to do if the range includes the default label until we
-        can register anti-ranges.  */
+      /* Can't extract a useful assertion out of a range that includes the
+        default label.  */
       if (min == NULL_TREE)
        continue;
 
@@ -5964,6 +5966,62 @@ find_switch_asserts (basic_block bb, gswitch *last)
     }
 
   XDELETEVEC (ci);
+
+  if (!live_on_edge (default_edge, op))
+    return;
+
+  /* Now register along the default label assertions that correspond to the
+     anti-range of each label.  */
+  int insertion_limit = PARAM_VALUE (PARAM_MAX_VRP_SWITCH_ASSERTIONS);
+  for (idx = 1; idx < n; idx++)
+    {
+      tree min, max;
+      tree cl = gimple_switch_label (last, idx);
+
+      min = CASE_LOW (cl);
+      max = CASE_HIGH (cl);
+
+      /* Combine contiguous case ranges to reduce the number of assertions
+        to insert.  */
+      for (idx = idx + 1; idx < n; idx++)
+       {
+         tree next_min, next_max;
+         tree next_cl = gimple_switch_label (last, idx);
+
+         next_min = CASE_LOW (next_cl);
+         next_max = CASE_HIGH (next_cl);
+
+         wide_int difference = wi::sub (next_min, max ? max : min);
+         if (wi::eq_p (difference, 1))
+           max = next_max ? next_max : next_min;
+         else
+           break;
+       }
+      idx--;
+
+      if (max == NULL_TREE)
+       {
+         /* Register the assertion OP != MIN.  */
+         min = fold_convert (TREE_TYPE (op), min);
+         register_edge_assert_for (op, default_edge, bsi, NE_EXPR, op, min);
+       }
+      else
+       {
+         /* Register the assertion (unsigned)OP - MIN > (MAX - MIN),
+            which will give OP the anti-range ~[MIN,MAX].  */
+         tree uop = fold_convert (unsigned_type_for (TREE_TYPE (op)), op);
+         min = fold_convert (TREE_TYPE (uop), min);
+         max = fold_convert (TREE_TYPE (uop), max);
+
+         tree lhs = fold_build2 (MINUS_EXPR, TREE_TYPE (uop), uop, min);
+         tree rhs = int_const_binop (MINUS_EXPR, max, min);
+         register_new_assert_for (op, lhs, GT_EXPR, rhs,
+                                  NULL, default_edge, bsi);
+       }
+
+      if (--insertion_limit == 0)
+       break;
+    }
 }