vrp: Handle VCE in vrp_simplify_cond_using_ranges [PR80635]
authorJakub Jelinek <jakub@redhat.com>
Thu, 25 Feb 2021 09:16:55 +0000 (10:16 +0100)
committerJakub Jelinek <jakub@redhat.com>
Thu, 25 Feb 2021 09:16:55 +0000 (10:16 +0100)
> So I wonder what other optimizations are prevented here?

> Why does uninit warn with VCE but not with NOP_EXPR?  Or does the
> warning disappear because of those other optimizations you mention?

The optimization that it prevents is in this particular case in tree-vrp.c
(vrp_simplify_cond_using_ranges):

      if (!is_gimple_assign (def_stmt)
          || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
        return;
so it punts on VIEW_CONVERT_EXPR, with NOP_EXPR it optimizes that:
  _9 = (bool) maybe_a$4_7;
  if (_9 != 0)
into:
  _9 = (bool) maybe_a$4_7;
  if (maybe_a$4_7 != 0)

Now, if I apply my patch but manually disable this
vrp_simplify_cond_using_ranges optimization, then the uninit warning is
back, so on the uninit side it is not about VIEW_CONVERT_EXPR vs. NOP_EXPR,
both are bad there, uninit wants the guarding condition to be
that SSA_NAME and not some demotion cast thereof.
We have:
  # maybe_a$m_6 = PHI <_5(4), maybe_a$m_4(D)(6)>
  # maybe_a$4_7 = PHI <1(4), 0(6)>
...
One of:
  _9 = VIEW_CONVERT_EXPR<bool>(maybe_a$4_7);
  if (_9 != 0)
or:
  _9 = (bool) maybe_a$4_7;
  if (_9 != 0)
or:
  if (maybe_a$4_7 != 0)
followed by:
    goto <bb 11>; [0.00%]
  else
    goto <bb 14>; [0.00%]
...
  <bb 11> [count: 0]:
  set (maybe_a$m_6);
and uninit wants to see that maybe_a$m_4(D) is not used if
bb 11 is encountered.

This patch fixes it by teaching vrp_simplify_cond_using_ranges
to handle VCE (when from an integral type) in addition to
NOP_EXPR/CONVERT_EXPR, of course as long as the VCE or demotion
doesn't change any values, i.e. when the range of the VCE or
conversion operand fits into the target type.

2021-02-25  Jakub Jelinek  <jakub@redhat.com>

PR tree-optimization/80635
* tree-vrp.c (vrp_simplify_cond_using_ranges): Also handle
VIEW_CONVERT_EXPR if modes are the same, innerop is integral and
has mode precision.

* g++.dg/warn/pr80635-1.C: New test.
* g++.dg/warn/pr80635-2.C: New test.

gcc/testsuite/g++.dg/warn/pr80635-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/pr80635-2.C [new file with mode: 0644]
gcc/tree-vrp.c

diff --git a/gcc/testsuite/g++.dg/warn/pr80635-1.C b/gcc/testsuite/g++.dg/warn/pr80635-1.C
new file mode 100644 (file)
index 0000000..8478791
--- /dev/null
@@ -0,0 +1,46 @@
+// PR tree-optimization/80635
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -Wmaybe-uninitialized" }
+
+using size_t = decltype (sizeof (1));
+inline void *operator new (size_t, void *p) { return p; }
+template<typename T>
+struct optional
+{
+  optional () : m_dummy (), live (false) {}
+  void emplace () { new (&m_item) T (); live = true; }
+  ~optional () { if (live) m_item.~T (); }
+
+  union
+  {
+    struct {} m_dummy;
+    T m_item;
+  };
+  bool live;
+};
+
+extern int get ();
+extern void set (int);
+
+struct A
+{
+  A () : m (get ()) {}
+  ~A () { set (m); }   // { dg-bogus "may be used uninitialized in this function" }
+
+  int m;
+};
+
+struct B
+{
+  B ();
+  ~B ();
+};
+
+void func ()
+{
+  optional<A> maybe_a;
+  optional<B> maybe_b;
+
+  maybe_a.emplace ();
+  maybe_b.emplace ();
+}
diff --git a/gcc/testsuite/g++.dg/warn/pr80635-2.C b/gcc/testsuite/g++.dg/warn/pr80635-2.C
new file mode 100644 (file)
index 0000000..9f57547
--- /dev/null
@@ -0,0 +1,31 @@
+// PR tree-optimization/80635
+// { dg-do compile { target c++17 } }
+// { dg-options "-O2 -Wmaybe-uninitialized" }
+
+#include <optional>
+
+extern int get ();
+extern void set (int);
+
+struct A
+{
+  A () : m (get ()) {}
+  ~A () { set (m); }   // { dg-bogus "may be used uninitialized in this function" }
+
+  int m;
+};
+
+struct B
+{
+  B ();
+  ~B ();
+};
+
+void func ()
+{
+  std::optional<A> maybe_a;
+  std::optional<B> maybe_b;
+
+  maybe_a.emplace ();
+  maybe_b.emplace ();
+}
index 53eaf9c..8d638ae 100644 (file)
@@ -4390,11 +4390,22 @@ vrp_simplify_cond_using_ranges (vr_values *query, gcond *stmt)
       gimple *def_stmt = SSA_NAME_DEF_STMT (op0);
       tree innerop;
 
-      if (!is_gimple_assign (def_stmt)
-         || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
+      if (!is_gimple_assign (def_stmt))
        return;
 
-      innerop = gimple_assign_rhs1 (def_stmt);
+      switch (gimple_assign_rhs_code (def_stmt))
+       {
+       CASE_CONVERT:
+         innerop = gimple_assign_rhs1 (def_stmt);
+         break;
+       case VIEW_CONVERT_EXPR:
+         innerop = TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0);
+         if (!INTEGRAL_TYPE_P (TREE_TYPE (innerop)))
+           return;
+         break;
+       default:
+         return;
+       }
 
       if (TREE_CODE (innerop) == SSA_NAME
          && !POINTER_TYPE_P (TREE_TYPE (innerop))