https://gcc.gnu.org/g:570b63276f6434df59c52da36b1581eb8b516762
commit r14-11864-g570b63276f6434df59c52da36b1581eb8b516762 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 0d90bab595fc..026dac45deda 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -8444,19 +8444,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) @@ -8476,7 +8478,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 debfd1d04355..209c8a1d76b5 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -1592,6 +1592,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;