https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126570
Bug ID: 126570
Summary: Wrong code in phiprop and scalar_storage_order
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: ---
I don't know how much we care about scalar_storage_order("big-endian") but here
is one:
/* (predicate applied to the wrong object).
gcc/tree-ssa-phiprop.cc:193, phiprop_insert_phi.
The only checks on the load being sunk are
tree-ssa-phiprop.cc:470 types_compatible_p (TREE_TYPE
(gimple_assign_lhs
(use_stmt)), type)
tree-ssa-phiprop.cc:479 !stmt_can_throw_internal (cfun, use_stmt)
tree-ssa-phiprop.cc:480 !gimple_has_volatile_ops (use_stmt)
and the replacement is then built from scratch on every incoming edge:
tmp = gimple_build_assign (new_var,
fold_build2 (MEM_REF, TREE_TYPE (rhs),
old_arg, TREE_OPERAND (rhs,
1)));
TREE_TYPE (rhs) and the alias-ptr/offset operand are carried over, which is
what makes the omission look deliberate, but REF_REVERSE_STORAGE_ORDER is a
flag on the MEM_REF NODE (tree.h:1137), not on its type, so
types_compatible_p cannot see it and the new load reads the object in host
byte order. Same root as wave2/01 in the sibling pass.
The bare MEM_REF carrying the flag comes from SRA's build_ref_for_offset
(tree-sra.cc:1959), taken because the two access paths to offset 0
(u.s.a and u.i[0]) clear grp_same_access_path.
aarch64-linux (little endian), GCC trunk 2f5ed1700.
-O1/-O2/-O3/-Os 0x04030201 BAD, bytes reversed
-O0, or any level with -fno-tree-phiprop 0x01020304 correct
phiprop dump shows the loss directly:
Inserting PHI for result of load u$s$a_5 = MEM <int> [(union U *)p_1];
for edge defining &x inserting load _12 = MEM <int> [(union U *)&x];
the original carries {rev}, the two inserted loads do not. */
struct S { int a; int v; } __attribute__((scalar_storage_order("big-endian")));
union U { struct S s; int i[2]; }
__attribute__((scalar_storage_order("big-endian")));
union U x, y;
__attribute__((noinline,noipa))
int f (int c, int k)
{
union U *p = c ? &x : &y;
union U u = *p;
if (k)
return u.s.a;
return u.i[0];
}
int main (void)
{
x.i[0] = 0x01020304;
y.i[0] = 0x05060708;
if (f (1, 0) != 0x01020304)
__builtin_abort ();
if (f (0, 1) != 0x05060708)
__builtin_abort ();
return 0;
}
aborts on aarch64 at -O2 and doesn't at -O0