On Fri, Sep 5, 2025 at 1:50 AM Andrew Pinski
<[email protected]> wrote:
>
> SRA likes to create VCE<bool>(a) when it comes to bool. This confuses
> a few different passes including jump threading and uninitialization
> warning. This removes the VCE in one case where it will help.
> Values outside of 0/1 with the VCE will produce undefined code so
> removing the VCE is always fine as we go from undefined to well defined
> and not introduce new undefined code.
>
> This fix is like what was done for PR 80635 but not depending on the VRP to
> do the work so it is fixed at -O1 too.
>
> Bootstrapped and tested on x86_64-linux-gnu.
>
> PR tree-optimization/105749
> PR tree-optimization/80635
>
> gcc/ChangeLog:
>
> * match.pd (`VCE<bool>(a) ==\!= 0`): New pattern.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/warn/pr80635-3.C: New test.
> * g++.dg/warn/pr80635-4.C: New test.
>
> Signed-off-by: Andrew Pinski <[email protected]>
> ---
> gcc/match.pd | 10 ++++++
> gcc/testsuite/g++.dg/warn/pr80635-3.C | 47 +++++++++++++++++++++++++++
> gcc/testsuite/g++.dg/warn/pr80635-4.C | 32 ++++++++++++++++++
> 3 files changed, 89 insertions(+)
> create mode 100644 gcc/testsuite/g++.dg/warn/pr80635-3.C
> create mode 100644 gcc/testsuite/g++.dg/warn/pr80635-4.C
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index b1d7a3a1b73..954e52d9562 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -2359,6 +2359,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> (bit_not (bit_not @0))
> (non_lvalue @0))
>
> +/* VCE<bool>(a) ==/!= false -> a ==/!= 0.
> + This is done as SRA likes to create VCE for boolean accesses
> + and it helps code gneration and uninitialized variable warnings. */
But it loses information? The reverse, VCE<int>(a) with a bool 'a'
would gain. So I don't quite understand the idea behind this pattern.
Isn't the problem in uninit/jump threading instead?
Richard.
> +(for neeq (ne eq)
> + (simplify
> + (neeq (view_convert@0 @1) integer_zerop)
> + (if (TREE_CODE (TREE_TYPE (@0)) == BOOLEAN_TYPE
> + && INTEGRAL_TYPE_P (TREE_TYPE (@1)))
> + (neeq @1 { build_zero_cst (TREE_TYPE (@1)); } ))))
> +
> /* zero_one_valued_p will match when a value is known to be either
> 0 or 1 including constants 0 or 1.
> Signed 1-bits includes -1 so they cannot match here. */
> diff --git a/gcc/testsuite/g++.dg/warn/pr80635-3.C
> b/gcc/testsuite/g++.dg/warn/pr80635-3.C
> new file mode 100644
> index 00000000000..64fd78bac5a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/pr80635-3.C
> @@ -0,0 +1,47 @@
> +// PR tree-optimization/80635
> +// { dg-do compile { target c++11 } }
> +// { dg-options "-O1 -Wmaybe-uninitialized" }
> +// This is the same as pr80635-1.C but at -O1 instead of -O2.
> +
> +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-4.C
> b/gcc/testsuite/g++.dg/warn/pr80635-4.C
> new file mode 100644
> index 00000000000..1f32b9ae034
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/pr80635-4.C
> @@ -0,0 +1,32 @@
> +// PR tree-optimization/80635
> +// { dg-do compile { target c++17 } }
> +// { dg-options "-O1 -Wmaybe-uninitialized" }
> +// This is the same as pr80635-2.C but at -O1 instead of -O2.
> +
> +#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 ();
> +}
> --
> 2.43.0
>