https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126554
Bug ID: 126554
Summary: GCC emits an unnecessary stack protector when
performing an atomic operation on a struct member
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: missed-optimization
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: arsen at gcc dot gnu.org
CC: pedro.falcato at gmail dot com
Target Milestone: ---
Target: x86_64-linux-gnu
consider the following:
struct foo { unsigned int x; };
void stack_protected(struct foo *p)
{
struct foo expected = {0};
__atomic_compare_exchange_n(&p->x, &expected.x, 1, false,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
}
void stack_unprotected(unsigned *p)
{
unsigned expected = 0;
__atomic_compare_exchange_n(p, &expected, 1, false, __ATOMIC_ACQUIRE,
__ATOMIC_RELAXED);
}
... these two functions should produce the same code, but the former emits a
stack protector.
this is because, in the former, 'expected' is considered addressable:
Breakpoint 5, add_stack_protection_conflicts () at
../../gcc/gcc/cfgexpand.cc:2341
2341 ret = true;
(gdb) list
2336 phase = XNEWVEC (unsigned char, n);
2337 for (i = 0; i < n; ++i)
2338 {
2339 phase[i] = stack_protect_decl_phase (stack_vars[i].decl);
2340 if (TREE_ADDRESSABLE (stack_vars[i].decl))
2341 ret = true;
2342 }
2343
2344 for (i = 0; i < n; ++i)
2345 {
(gdb) p stack_vars[i].decl
$1 = <var_decl 0x7ffff6bd6e40 expected>
(gdb)
... this ret = true later leads to:
has_addressable_vars = add_stack_protection_conflicts ();
if (flag_stack_protect == SPCT_FLAG_STRONG && has_addressable_vars)
gen_stack_protect_signal = true;
ISTM that PR105495 is a similar case, though it manifests differently