https://gcc.gnu.org/g:2666791289e679bc48de67d9546783c07cc65f30

commit r13-9774-g2666791289e679bc48de67d9546783c07cc65f30
Author: Eric Botcazou <ebotca...@adacore.com>
Date:   Fri Jun 27 23:47:49 2025 +0200

    Fix misoptimization of CONSTRUCTOR with reverse SSO
    
    fold_ctor_reference already punts on a CONSTRUCTOR whose type has reverse
    storage order, but it can be invoked in a couple of places on a CONSTRUCTOR
    with native storage order that has been wrapped in a VIEW_CONVERT_EXPR to a
    type with reverse storage order; this would require a post adjustment that
    does not currently exist, thus yield wrong code for this admittedly quite
    pathological (but supported) case.
    
    gcc/
            * gimple-fold.cc (fold_const_aggregate_ref_1) <COMPONENT_REF>:
            Bail out immediately if the reference has reverse storage order.
            * tree-ssa-sccvn.cc (fully_constant_vn_reference_p): Likewise.
    gcc/testsuite/
            * gnat.dg/sso20.adb: New test.

Diff:
---
 gcc/gimple-fold.cc              | 13 +++++++------
 gcc/testsuite/gnat.dg/sso20.adb | 29 +++++++++++++++++++++++++++++
 gcc/tree-ssa-sccvn.cc           |  2 ++
 3 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 180817cc8680..1387e03d92bd 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -8339,19 +8339,21 @@ fold_const_aggregate_ref_1 (tree t, tree (*valueize) 
(tree))
       base = get_ref_base_and_extent (t, &offset, &size, &max_size, &reverse);
       ctor = get_base_constructor (base, &offset, valueize);
 
+      /* We cannot determine ctor.  */
+      if (!ctor)
+       return NULL_TREE;
       /* Empty constructor.  Always fold to 0.  */
       if (ctor == error_mark_node)
        return build_zero_cst (TREE_TYPE (t));
-      /* We do not know precise address.  */
+      /* We do not know precise access.  */
       if (!known_size_p (max_size) || maybe_ne (max_size, size))
        return NULL_TREE;
-      /* We cannot determine ctor.  */
-      if (!ctor)
-       return NULL_TREE;
-
       /* Out of bound array access.  Value is undefined, but don't fold.  */
       if (maybe_lt (offset, 0))
        return NULL_TREE;
+      /* Access with reverse storage order.  */
+      if (reverse)
+       return NULL_TREE;
 
       tem = fold_ctor_reference (TREE_TYPE (t), ctor, offset, size, base);
       if (tem)
@@ -8371,7 +8373,6 @@ fold_const_aggregate_ref_1 (tree t, tree (*valueize) 
(tree))
              && offset.is_constant (&coffset)
              && (coffset % BITS_PER_UNIT != 0
                  || csize % BITS_PER_UNIT != 0)
-             && !reverse
              && BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN)
            {
              poly_int64 bitoffset;
diff --git a/gcc/testsuite/gnat.dg/sso20.adb b/gcc/testsuite/gnat.dg/sso20.adb
new file mode 100644
index 000000000000..34980d35d874
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/sso20.adb
@@ -0,0 +1,29 @@
+--  { dg-do run }
+--  { dg-options "-O" }
+
+with Ada.Unchecked_Conversion;
+with Interfaces;  use Interfaces;
+with System;      use System;
+
+procedure SSO20 is
+
+  type Bytes_Ref is array (1 .. 4) of Unsigned_8
+    with Convention => Ada_Pass_By_Reference;
+
+  type U32_BE is record
+    Value : Unsigned_32;
+  end record
+    with
+      Pack,
+      Bit_Order            => High_Order_First,
+      Scalar_Storage_Order => High_Order_First;
+
+  function Conv is new Ada.Unchecked_Conversion (Bytes_Ref, U32_BE);
+
+  function Value (B : Bytes_Ref) return Unsigned_32 is (Conv (B).Value);
+
+begin
+  if Value ((16#11#, 16#22#, 16#33#, 16#44#)) /= 16#11223344# then
+     raise Program_Error;
+  end if;
+end;
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index a526268e0780..68b0bdce4e9b 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -1576,6 +1576,8 @@ fully_constant_vn_reference_p (vn_reference_t ref)
              ++i;
              break;
            }
+         if (operands[i].reverse)
+           return NULL_TREE;
          if (known_eq (operands[i].off, -1))
            return NULL_TREE;
          off += operands[i].off;

Reply via email to