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

Reply via email to