https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126567
Bug ID: 126567
Summary: [17 Regression] Wrong code with
factor_out_conditional_load
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: ktkachov at gcc dot gnu.org
Target Milestone: ---
/* Wrong code: factor_out_conditional_load () in gcc/tree-ssa-phiopt.cc moves a
conditional load past a store that follows it in the same arm.
When get_virtual_phi (merge) is non-NULL the transform demands
gimple_vuse (loadN) == the virtual PHI argument on edge eN
which proves there is no VDEF between the load and the merge. When the
merge block has no virtual PHI the only check left is
gimple_vuse (load0) == gimple_vuse (load1)
(tree-ssa-phiopt.cc:4170), which says nothing about statements AFTER the
load. is_factor_profitable () tolerates up to
--param=phiopt-factor-max-stmts-live further GIMPLE_ASSIGNs in the arm, and
a store is a GIMPLE_ASSIGN, so the factored load is inserted at
gsi_after_labels (merge), physically behind that store, and reads the
post-store value.
Every sibling in the file (cond_store_replacement_limited,
cselim_candidate, cond_if_else_store_replacement_limited,
cond_if_else_store_replacement) bails out when get_virtual_phi is NULL.
To reach the no-virtual-PHI path .MEM must be dead at the merge, so nothing
after the merge may touch memory. That rules out abort(), a return, or any
volatile access as the reporting channel: each of them keeps .MEM live and
makes the virtual PHI reappear. The result is therefore reported through
the process exit status with a register-only exit syscall.
Correct behaviour: exit status 0. Miscompiled: exit status 1.
-O1 and above; needs the late phiopt, so -fno-ssa-phiopt makes it pass. */
int a, b;
#if defined(__aarch64__)
#define EXIT_WITH(x) \
__asm__ __volatile__ ("mov x8, 94\n\tmov w0, %w0\n\tsvc 0" \
:: "r" (x) : "x0", "x8")
#elif defined(__x86_64__)
#define EXIT_WITH(x) \
__asm__ __volatile__ ("syscall" :: "a" (60), "D" (x) : "rcx", "r11")
#else
#define EXIT_WITH(x) __builtin_exit (x) /* has a VDEF, will not trigger */
#endif
__attribute__((noipa, noreturn))
static void f (int c, int *p, int *r, int want)
{
int v;
if (c)
{
v = *p; /* must read the value BEFORE the store */
*p = 7;
}
else
v = *r;
/* No memory operand from here on: .MEM is dead at the merge block, so
into-SSA never puts a virtual PHI there. */
for (;;)
EXIT_WITH (v != want);
}
int main (void)
{
volatile int five = 5, nine = 9;
a = five;
b = nine;
f (1, &a, &b, five);
}
This exits on aarch64 with status code 1 at -O1 and above and status code 0 at
-O0