[RFC] tree-optimization/105646 - re-interpret always executed in uninit diag
Commit Message
The following fixes PR105646, not diagnosing
int f1();
int f3(){
auto const & a = f1();
bool v3{v3};
return a;
}
with optimization because the early uninit diagnostic pass only
diagnoses always executed cases. The patch does this by
re-interpreting what always executed means and choosing to
ignore exceptional and abnormal control flow for this. At the
same time it improves things as suggested in a comment - when
the value-numbering run done without optimizing figures there's
a fallthru path, consider blocks on it as always executed.
Bootstrapped and tested on x86_64-unknown-linux-gnu.
OK?
Thanks,
Richard.
PR tree-optimization/105646
* tree-ssa-uninit.cc (warn_uninitialized_vars): Pre-compute
the set of fallthru reachable blocks from function entry
and use that to determine wlims.always_executed.
* g++.dg/uninit-pr105646.C: New testcase.
---
gcc/testsuite/g++.dg/uninit-pr105646.C | 17 +++++++++
gcc/tree-ssa-uninit.cc | 53 +++++++++++++++++++++-----
2 files changed, 61 insertions(+), 9 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/uninit-pr105646.C
Comments
On 8/22/22 00:16, Richard Biener via Gcc-patches wrote:
> The following fixes PR105646, not diagnosing
>
> int f1();
> int f3(){
> auto const & a = f1();
> bool v3{v3};
> return a;
> }
>
> with optimization because the early uninit diagnostic pass only
> diagnoses always executed cases. The patch does this by
> re-interpreting what always executed means and choosing to
> ignore exceptional and abnormal control flow for this. At the
> same time it improves things as suggested in a comment - when
> the value-numbering run done without optimizing figures there's
> a fallthru path, consider blocks on it as always executed.
>
> Bootstrapped and tested on x86_64-unknown-linux-gnu.
>
> OK?
>
> Thanks,
> Richard.
>
> PR tree-optimization/105646
> * tree-ssa-uninit.cc (warn_uninitialized_vars): Pre-compute
> the set of fallthru reachable blocks from function entry
> and use that to determine wlims.always_executed.
>
> * g++.dg/uninit-pr105646.C: New testcase.
I'm torn on this. On one hand, ignoring abnormal flow control in the
early pass is almost certainly going to result in false positives but
it's also going to result in fixing some false negatives.
I'm willing to ACK and see what the real world fallout is in the spring
when the distros run their builds. Your call.
Jeff
On Tue, Sep 27, 2022 at 5:48 PM Jeff Law via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
>
> On 8/22/22 00:16, Richard Biener via Gcc-patches wrote:
> > The following fixes PR105646, not diagnosing
> >
> > int f1();
> > int f3(){
> > auto const & a = f1();
> > bool v3{v3};
> > return a;
> > }
> >
> > with optimization because the early uninit diagnostic pass only
> > diagnoses always executed cases. The patch does this by
> > re-interpreting what always executed means and choosing to
> > ignore exceptional and abnormal control flow for this. At the
> > same time it improves things as suggested in a comment - when
> > the value-numbering run done without optimizing figures there's
> > a fallthru path, consider blocks on it as always executed.
> >
> > Bootstrapped and tested on x86_64-unknown-linux-gnu.
> >
> > OK?
> >
> > Thanks,
> > Richard.
> >
> > PR tree-optimization/105646
> > * tree-ssa-uninit.cc (warn_uninitialized_vars): Pre-compute
> > the set of fallthru reachable blocks from function entry
> > and use that to determine wlims.always_executed.
> >
> > * g++.dg/uninit-pr105646.C: New testcase.
>
> I'm torn on this. On one hand, ignoring abnormal flow control in the
> early pass is almost certainly going to result in false positives but
> it's also going to result in fixing some false negatives.
>
> I'm willing to ACK and see what the real world fallout is in the spring
> when the distros run their builds. Your call.
I have pushed this now after retesting. Let's see if there's any bad
fallout - we can certainly reconsider.
Richard.
>
> Jeff
>
>
new file mode 100644
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-require-effective-target c++11 }
+// { dg-options "-O2 -Wuninitialized" }
+
+int f1();
+int f2(){
+ bool v2{v2}; // { dg-warning "is used uninitialized" }
+ auto const & a = f1();
+ return a;
+}
+int f3(){
+ auto const & a = f1();
+ // Diagnose the following when optimizing and as unconditional
+ // uninitialized use despite f1 possibly throwing
+ bool v3{v3}; // { dg-warning "is used uninitialized" }
+ return a;
+}
@@ -987,10 +987,49 @@ warn_uninitialized_vars (bool wmaybe_uninit)
wlimits wlims = { };
wlims.wmaybe_uninit = wmaybe_uninit;
- gimple_stmt_iterator gsi;
- basic_block bb;
+ auto_bb_flag ft_reachable (cfun);
+
+ /* Mark blocks that are always executed when we ignore provably
+ not executed and EH and abnormal edges. */
+ basic_block bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ while (!(bb->flags & ft_reachable))
+ {
+ bb->flags |= ft_reachable;
+ edge e = find_fallthru_edge (bb->succs);
+ if (e && e->flags & EDGE_EXECUTABLE)
+ {
+ bb = e->dest;
+ continue;
+ }
+ /* Find a single executable edge. */
+ edge_iterator ei;
+ edge ee = NULL;
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ if (e->flags & EDGE_EXECUTABLE)
+ {
+ if (!ee)
+ ee = e;
+ else
+ {
+ ee = NULL;
+ break;
+ }
+ }
+ if (ee)
+ bb = ee->dest;
+ else
+ {
+ bb = get_immediate_dominator (CDI_POST_DOMINATORS, bb);
+ if (!bb || bb->index == EXIT_BLOCK)
+ break;
+ }
+ }
+
FOR_EACH_BB_FN (bb, cfun)
{
+ wlims.always_executed = (bb->flags & ft_reachable);
+ bb->flags &= ~ft_reachable;
+
edge_iterator ei;
edge e;
FOR_EACH_EDGE (e, ei, bb->preds)
@@ -1001,14 +1040,10 @@ warn_uninitialized_vars (bool wmaybe_uninit)
if (!e)
continue;
- basic_block succ = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
- /* ??? This could be improved when we use a greedy walk and have
- some edges marked as not executable. */
- wlims.always_executed = dominated_by_p (CDI_POST_DOMINATORS, succ, bb);
-
if (wlims.always_executed)
warn_uninit_phi_uses (bb);
+ gimple_stmt_iterator gsi;
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple *stmt = gsi_stmt (gsi);
@@ -1029,7 +1064,7 @@ warn_uninitialized_vars (bool wmaybe_uninit)
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, op_iter, SSA_OP_USE)
{
/* BIT_INSERT_EXPR first operand should not be considered
- a use for the purpose of uninit warnings. */
+ a use for the purpose of uninit warnings. */
if (gassign *ass = dyn_cast <gassign *> (stmt))
{
if (gimple_assign_rhs_code (ass) == BIT_INSERT_EXPR
@@ -1040,7 +1075,7 @@ warn_uninitialized_vars (bool wmaybe_uninit)
if (wlims.always_executed)
warn_uninit (OPT_Wuninitialized, use,
SSA_NAME_VAR (use), stmt);
- else if (wmaybe_uninit)
+ else if (wlims.wmaybe_uninit)
warn_uninit (OPT_Wmaybe_uninitialized, use,
SSA_NAME_VAR (use), stmt);
}