Hi!
remove_unused_locals ignores clobbers in the initial phase (and
some debug stmts) and this has been copied for .DEFERRED_INIT
as well:
if (gimple_clobber_p (stmt))
{
have_local_clobbers = true;
continue;
}
if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
{
have_local_clobbers = true;
continue;
}
This is so that the second phase can then drop clobbers that
clobber unused local vars and ditto for .DEFERRED_INIT.
Except, for clobbers it does
/* Remove clobbers referencing unused vars, or clobbers
with MEM_REF lhs referencing uninitialized pointers. */
if ((VAR_P (base) && !is_used_p (base))
|| (TREE_CODE (lhs) == MEM_REF
&& TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME
&& SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (lhs, 0))
&& (TREE_CODE (SSA_NAME_VAR (TREE_OPERAND (lhs, 0)))
!= PARM_DECL)))
so handles both the var = {CLOBBER}; case where var is unused local,
or *SSA_NAME = {CLOBBER} where SSA_NAME is default definition of
non-PARM_DECL, but for .DEFERRED_INIT it doesn't:
if (DECL_P (base) && !is_used_p (base))
On the following case, we have *SSA_NAME(D) = .DEFERRED_INIT (...);
and because of the former we don't mark the SSA_NAME as used and
because of the latter we keep the .DEFERRED_INIT call, so the SSA_NAME
is freed and later on we ICE because the SSA_NAME in the freelist doesn't
have SSA_NAME_DEF_STMT.
The following patch fixes it by handling .DEFERRED_INIT like clobbers
and dropping them also when it has a MEM_REF with default definition
of SSA_NAME for non-PARM_DECL on the lhs.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2025-11-19 Jakub Jelinek <[email protected]>
PR tree-optimization/122184
* tree-ssa-live.cc (remove_unused_locals): Drop .DEFERRED_INIT
calls with MEM_REF lhs based on uninitialized SSA_NAME.
* g++.dg/opt/pr122184-1.C: New test.
* g++.dg/opt/pr122184-2.C: New test.
--- gcc/tree-ssa-live.cc.jj 2025-07-07 11:04:58.566699746 +0200
+++ gcc/tree-ssa-live.cc 2025-11-18 13:43:26.938709025 +0100
@@ -926,7 +926,12 @@ remove_unused_locals (void)
{
tree lhs = gimple_call_lhs (stmt);
tree base = get_base_address (lhs);
- if (DECL_P (base) && !is_used_p (base))
+ if ((DECL_P (base) && !is_used_p (base))
+ || (TREE_CODE (lhs) == MEM_REF
+ && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME
+ && SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (lhs, 0))
+ && (TREE_CODE (SSA_NAME_VAR (TREE_OPERAND (lhs, 0)))
+ != PARM_DECL)))
{
unlink_stmt_vdef (stmt);
gsi_remove (&gsi, true);
--- gcc/testsuite/g++.dg/opt/pr122184-1.C.jj 2025-11-18 13:50:16.496894332
+0100
+++ gcc/testsuite/g++.dg/opt/pr122184-1.C 2025-11-18 13:49:42.515376787
+0100
@@ -0,0 +1,12 @@
+// PR tree-optimization/122184
+// { dg-do compile }
+// { dg-require-stack-check "generic" }
+// { dg-options "-O2 -fstack-check=generic" }
+
+void
+foo ()
+{
+ goto fail;
+ char var[41];
+fail:;
+}
--- gcc/testsuite/g++.dg/opt/pr122184-2.C.jj 2025-11-18 14:18:10.642137383
+0100
+++ gcc/testsuite/g++.dg/opt/pr122184-2.C 2025-11-18 14:18:30.539854977
+0100
@@ -0,0 +1,12 @@
+// PR tree-optimization/122184
+// { dg-do compile }
+// { dg-require-stack-check "generic" }
+// { dg-options "-O2 -fstack-check=generic -ftrivial-auto-var-init=zero" }
+
+void
+foo ()
+{
+ goto fail;
+ char var[41];
+fail:;
+}
Jakub